Merge remote-tracking branch 'origin/main' into feat/login_hint_with_email
This commit is contained in:
20
.github/workflows/build.yaml
vendored
20
.github/workflows/build.yaml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# Need a full clone so that `git describe` reports the right version
|
||||
fetch-depth: 0
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/build-frontend
|
||||
- uses: ./.github/actions/build-policies
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -162,19 +162,19 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download assets
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: assets
|
||||
path: assets-dist
|
||||
|
||||
- name: Download binary x86_64
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: binary-x86_64-unknown-linux-gnu
|
||||
path: binary-x86_64
|
||||
|
||||
- name: Download binary aarch64
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: binary-aarch64-unknown-linux-gnu
|
||||
path: binary-aarch64
|
||||
@@ -320,7 +320,7 @@ jobs:
|
||||
- build-image
|
||||
steps:
|
||||
- name: Download the artifacts from the previous job
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
pattern: mas-cli-*
|
||||
path: artifacts
|
||||
@@ -376,13 +376,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts
|
||||
|
||||
- name: Download the artifacts from the previous job
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
pattern: mas-cli-*
|
||||
path: artifacts
|
||||
@@ -454,7 +454,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts
|
||||
|
||||
26
.github/workflows/ci.yaml
vendored
26
.github/workflows/ci.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/build-policies
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
@@ -155,10 +155,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Run `cargo-deny`
|
||||
uses: EmbarkStudios/cargo-deny-action@v2.0.12
|
||||
uses: EmbarkStudios/cargo-deny-action@v2.0.13
|
||||
with:
|
||||
rust-version: stable
|
||||
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
run: |
|
||||
@@ -212,10 +212,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@1.87.0
|
||||
uses: dtolnay/rust-toolchain@1.89.0
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -290,7 +290,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -304,7 +304,7 @@ jobs:
|
||||
- uses: ./.github/actions/build-policies
|
||||
|
||||
- name: Download archive
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nextest-archive
|
||||
|
||||
|
||||
6
.github/workflows/coverage.yaml
vendored
6
.github/workflows/coverage.yaml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/build-policies
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/build-frontend
|
||||
env:
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
4
.github/workflows/docs.yaml
vendored
4
.github/workflows/docs.yaml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Upload GitHub Pages artifacts
|
||||
uses: actions/upload-pages-artifact@v3.0.1
|
||||
uses: actions/upload-pages-artifact@v4.0.0
|
||||
with:
|
||||
path: target/book/
|
||||
|
||||
|
||||
2
.github/workflows/merge-back.yaml
vendored
2
.github/workflows/merge-back.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts
|
||||
|
||||
6
.github/workflows/release-branch.yaml
vendored
6
.github/workflows/release-branch.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
run: exit 1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
needs: [tag, compute-version, localazy]
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts
|
||||
|
||||
4
.github/workflows/release-bump.yaml
vendored
4
.github/workflows/release-bump.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
run: exit 1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
needs: [tag, compute-version]
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts
|
||||
|
||||
2
.github/workflows/tag.yaml
vendored
2
.github/workflows/tag.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
2
.github/workflows/translations-download.yaml
vendored
2
.github/workflows/translations-download.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
run: exit 1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
|
||||
2
.github/workflows/translations-upload.yaml
vendored
2
.github/workflows/translations-upload.yaml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4.4.0
|
||||
|
||||
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -831,9 +831,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
|
||||
checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -980,9 +980,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.42"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
|
||||
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -990,9 +990,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.42"
|
||||
version = "4.5.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
|
||||
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1002,9 +1002,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.41"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
|
||||
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -2084,9 +2084,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cbe789d04bf14543f03c4b60cd494148aa79438c8440ae7d81a7778147745c3"
|
||||
checksum = "444405bbb1a762387aa22dd569429533b54a1d8759d35d3b64cb39b0293eaa19"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dashmap",
|
||||
|
||||
@@ -137,7 +137,7 @@ version = "1.10.1"
|
||||
|
||||
# UTF-8 paths
|
||||
[workspace.dependencies.camino]
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
features = ["serde1"]
|
||||
|
||||
# ChaCha20Poly1305 AEAD
|
||||
@@ -167,7 +167,7 @@ features = ["serde", "clock"]
|
||||
|
||||
# CLI argument parsing
|
||||
[workspace.dependencies.clap]
|
||||
version = "4.5.42"
|
||||
version = "4.5.45"
|
||||
features = ["derive"]
|
||||
|
||||
# Object Identifiers (OIDs) as constants
|
||||
@@ -239,7 +239,7 @@ version = "0.14.7"
|
||||
|
||||
# Rate-limiting
|
||||
[workspace.dependencies.governor]
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
default-features = false
|
||||
features = ["std", "dashmap", "quanta"]
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# The Debian version and version name must be in sync
|
||||
ARG DEBIAN_VERSION=12
|
||||
ARG DEBIAN_VERSION_NAME=bookworm
|
||||
ARG RUSTC_VERSION=1.87.0
|
||||
ARG RUSTC_VERSION=1.89.0
|
||||
ARG NODEJS_VERSION=20.15.0
|
||||
ARG OPA_VERSION=1.1.0
|
||||
ARG CARGO_AUDITABLE_VERSION=0.6.6
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
# Please see LICENSE files in the repository root for full details.
|
||||
|
||||
doc-valid-idents = ["OpenID", "OAuth", "..", "PostgreSQL", "SQLite"]
|
||||
doc-valid-idents = ["OpenID", "OAuth", "UserInfo", "..", "PostgreSQL", "SQLite"]
|
||||
|
||||
disallowed-methods = [
|
||||
{ path = "rand::thread_rng", reason = "do not create rngs on the fly, pass them as parameters" },
|
||||
|
||||
@@ -12,13 +12,13 @@ fn main() -> anyhow::Result<()> {
|
||||
// At build time, we override the version through the environment variable
|
||||
// VERGEN_GIT_DESCRIBE. In some contexts, it means this variable is set but
|
||||
// empty, so we unset it here.
|
||||
if let Ok(ver) = std::env::var("VERGEN_GIT_DESCRIBE") {
|
||||
if ver.is_empty() {
|
||||
#[allow(unsafe_code)]
|
||||
// SAFETY: This is safe because the build script is running a single thread
|
||||
unsafe {
|
||||
std::env::remove_var("VERGEN_GIT_DESCRIBE");
|
||||
}
|
||||
if let Ok(ver) = std::env::var("VERGEN_GIT_DESCRIBE")
|
||||
&& ver.is_empty()
|
||||
{
|
||||
#[allow(unsafe_code)]
|
||||
// SAFETY: This is safe because the build script is running a single thread
|
||||
unsafe {
|
||||
std::env::remove_var("VERGEN_GIT_DESCRIBE");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,10 +273,10 @@ fn infer_client_ip(
|
||||
|
||||
let peer = if let Some(info) = connection_info {
|
||||
// We can always trust the proxy protocol to give us the correct IP address
|
||||
if let Some(proxy) = info.get_proxy_ref() {
|
||||
if let Some(source) = proxy.source() {
|
||||
return Some(source.ip());
|
||||
}
|
||||
if let Some(proxy) = info.get_proxy_ref()
|
||||
&& let Some(source) = proxy.source()
|
||||
{
|
||||
return Some(source.ip());
|
||||
}
|
||||
|
||||
info.get_peer_addr().map(|addr| addr.ip())
|
||||
|
||||
@@ -619,13 +619,12 @@ impl Options {
|
||||
let txn = conn.begin().await?;
|
||||
let mut repo = PgRepository::from_conn(txn);
|
||||
|
||||
if let Some(password) = &password {
|
||||
if !ignore_password_complexity
|
||||
&& !password_manager.is_password_complex_enough(password)?
|
||||
{
|
||||
error!("That password is too weak.");
|
||||
return Ok(ExitCode::from(1));
|
||||
}
|
||||
if let Some(password) = &password
|
||||
&& !ignore_password_complexity
|
||||
&& !password_manager.is_password_complex_enough(password)?
|
||||
{
|
||||
error!("That password is too weak.");
|
||||
return Ok(ExitCode::from(1));
|
||||
}
|
||||
|
||||
// If the username is provided, check if it's available and normalize it.
|
||||
|
||||
@@ -209,11 +209,11 @@ pub async fn config_sync(
|
||||
// private key to hold the content of the private key file.
|
||||
// private key (raw) takes precedence so both can be defined
|
||||
// without issues
|
||||
if siwa.private_key.is_none() {
|
||||
if let Some(private_key_file) = siwa.private_key_file.take() {
|
||||
let key = tokio::fs::read_to_string(private_key_file).await?;
|
||||
siwa.private_key = Some(key);
|
||||
}
|
||||
if siwa.private_key.is_none()
|
||||
&& let Some(private_key_file) = siwa.private_key_file.take()
|
||||
{
|
||||
let key = tokio::fs::read_to_string(private_key_file).await?;
|
||||
siwa.private_key = Some(key);
|
||||
}
|
||||
let encoded = serde_json::to_vec(&siwa)?;
|
||||
Some(encrypter.encrypt_to_string(&encoded)?)
|
||||
|
||||
@@ -149,7 +149,7 @@ impl KeyConfig {
|
||||
/// Returns the password in case any is provided.
|
||||
///
|
||||
/// If `password_file` was given, the password is read from that file.
|
||||
async fn password(&self) -> anyhow::Result<Option<Cow<[u8]>>> {
|
||||
async fn password(&self) -> anyhow::Result<Option<Cow<'_, [u8]>>> {
|
||||
Ok(match &self.password {
|
||||
Some(Password::File(path)) => Some(Cow::Owned(tokio::fs::read(path).await?)),
|
||||
Some(Password::Value(password)) => Some(Cow::Borrowed(password.as_bytes())),
|
||||
@@ -160,7 +160,7 @@ impl KeyConfig {
|
||||
/// Returns the key.
|
||||
///
|
||||
/// If `key_file` was given, the key is read from that file.
|
||||
async fn key(&self) -> anyhow::Result<Cow<[u8]>> {
|
||||
async fn key(&self) -> anyhow::Result<Cow<'_, [u8]>> {
|
||||
Ok(match &self.key {
|
||||
Key::File(path) => Cow::Owned(tokio::fs::read(path).await?),
|
||||
Key::Value(key) => Cow::Borrowed(key.as_bytes()),
|
||||
|
||||
@@ -198,34 +198,34 @@ impl ConfigurationSection for TelemetryConfig {
|
||||
&self,
|
||||
_figment: &figment::Figment,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
if let Some(sample_rate) = self.sentry.sample_rate {
|
||||
if !(0.0..=1.0).contains(&sample_rate) {
|
||||
return Err(figment::error::Error::custom(
|
||||
"Sentry sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("sentry.sample_rate")
|
||||
.into());
|
||||
}
|
||||
if let Some(sample_rate) = self.sentry.sample_rate
|
||||
&& !(0.0..=1.0).contains(&sample_rate)
|
||||
{
|
||||
return Err(figment::error::Error::custom(
|
||||
"Sentry sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("sentry.sample_rate")
|
||||
.into());
|
||||
}
|
||||
|
||||
if let Some(sample_rate) = self.sentry.traces_sample_rate {
|
||||
if !(0.0..=1.0).contains(&sample_rate) {
|
||||
return Err(figment::error::Error::custom(
|
||||
"Sentry sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("sentry.traces_sample_rate")
|
||||
.into());
|
||||
}
|
||||
if let Some(sample_rate) = self.sentry.traces_sample_rate
|
||||
&& !(0.0..=1.0).contains(&sample_rate)
|
||||
{
|
||||
return Err(figment::error::Error::custom(
|
||||
"Sentry sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("sentry.traces_sample_rate")
|
||||
.into());
|
||||
}
|
||||
|
||||
if let Some(sample_rate) = self.tracing.sample_rate {
|
||||
if !(0.0..=1.0).contains(&sample_rate) {
|
||||
return Err(figment::error::Error::custom(
|
||||
"Tracing sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("tracing.sample_rate")
|
||||
.into());
|
||||
}
|
||||
if let Some(sample_rate) = self.tracing.sample_rate
|
||||
&& !(0.0..=1.0).contains(&sample_rate)
|
||||
{
|
||||
return Err(figment::error::Error::custom(
|
||||
"Tracing sample rate must be between 0.0 and 1.0",
|
||||
)
|
||||
.with_path("tracing.sample_rate")
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -652,7 +652,7 @@ pub struct Provider {
|
||||
|
||||
/// What to do when receiving an OIDC Backchannel logout request.
|
||||
///
|
||||
/// Defaults to "do_nothing".
|
||||
/// Defaults to `do_nothing`.
|
||||
#[serde(default, skip_serializing_if = "OnBackchannelLogout::is_default")]
|
||||
pub on_backchannel_logout: OnBackchannelLogout,
|
||||
}
|
||||
|
||||
@@ -129,31 +129,31 @@ where
|
||||
field_fromatter.format_fields(writer.by_ref(), event)?;
|
||||
|
||||
// If we have a OTEL span, we can add the trace ID to the end of the log line
|
||||
if let Some(span) = ctx.lookup_current() {
|
||||
if let Some(otel) = span.extensions().get::<OtelData>() {
|
||||
let parent_cx_span = otel.parent_cx.span();
|
||||
let sc = parent_cx_span.span_context();
|
||||
if let Some(span) = ctx.lookup_current()
|
||||
&& let Some(otel) = span.extensions().get::<OtelData>()
|
||||
{
|
||||
let parent_cx_span = otel.parent_cx.span();
|
||||
let sc = parent_cx_span.span_context();
|
||||
|
||||
// Check if the span is sampled, first from the span builder,
|
||||
// then from the parent context if nothing is set there
|
||||
if otel
|
||||
.builder
|
||||
.sampling_result
|
||||
.as_ref()
|
||||
.map_or(sc.is_sampled(), |r| {
|
||||
r.decision == SamplingDecision::RecordAndSample
|
||||
})
|
||||
{
|
||||
// If it is the root span, the trace ID will be in the span builder. Else, it
|
||||
// will be in the parent OTEL context
|
||||
let trace_id = otel.builder.trace_id.unwrap_or(sc.trace_id());
|
||||
if trace_id != TraceId::INVALID {
|
||||
let label = Style::new()
|
||||
.italic()
|
||||
.force_styling(ansi)
|
||||
.apply_to("trace.id");
|
||||
write!(&mut writer, " {label}={trace_id}")?;
|
||||
}
|
||||
// Check if the span is sampled, first from the span builder,
|
||||
// then from the parent context if nothing is set there
|
||||
if otel
|
||||
.builder
|
||||
.sampling_result
|
||||
.as_ref()
|
||||
.map_or(sc.is_sampled(), |r| {
|
||||
r.decision == SamplingDecision::RecordAndSample
|
||||
})
|
||||
{
|
||||
// If it is the root span, the trace ID will be in the span builder. Else, it
|
||||
// will be in the parent OTEL context
|
||||
let trace_id = otel.builder.trace_id.unwrap_or(sc.trace_id());
|
||||
if trace_id != TraceId::INVALID {
|
||||
let label = Style::new()
|
||||
.italic()
|
||||
.force_styling(ansi)
|
||||
.apply_to("trace.id");
|
||||
write!(&mut writer, " {label}={trace_id}")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ impl AuthorizationGrant {
|
||||
///
|
||||
/// Otherwise returns `LoginHint::None`
|
||||
#[must_use]
|
||||
pub fn parse_login_hint(&self, homeserver: &str) -> LoginHint {
|
||||
pub fn parse_login_hint(&self, homeserver: &str) -> LoginHint<'_> {
|
||||
let Some(login_hint) = &self.login_hint else {
|
||||
return LoginHint::None;
|
||||
};
|
||||
|
||||
@@ -289,7 +289,7 @@ pub struct UpstreamOAuthProvider {
|
||||
|
||||
impl PartialOrd for UpstreamOAuthProvider {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.id.cmp(&other.id))
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,32 +88,31 @@ impl UserAgent {
|
||||
|
||||
#[must_use]
|
||||
pub fn parse(user_agent: String) -> Self {
|
||||
if !user_agent.contains("Mozilla/") {
|
||||
if let Some((name, version, model, os, os_version)) =
|
||||
if !user_agent.contains("Mozilla/")
|
||||
&& let Some((name, version, model, os, os_version)) =
|
||||
UserAgent::parse_custom(&user_agent)
|
||||
{
|
||||
let mut device_type = DeviceType::Unknown;
|
||||
{
|
||||
let mut device_type = DeviceType::Unknown;
|
||||
|
||||
// Handle mobile simple mobile devices
|
||||
if os == "Android" || os == "iOS" {
|
||||
device_type = DeviceType::Mobile;
|
||||
}
|
||||
|
||||
// Handle iPads
|
||||
if model.contains("iPad") {
|
||||
device_type = DeviceType::Tablet;
|
||||
}
|
||||
|
||||
return Self {
|
||||
name: Some(name.to_owned()),
|
||||
version: Some(version.to_owned()),
|
||||
os: Some(os.to_owned()),
|
||||
os_version: os_version.map(std::borrow::ToOwned::to_owned),
|
||||
model: Some(model.to_owned()),
|
||||
device_type,
|
||||
raw: user_agent,
|
||||
};
|
||||
// Handle mobile simple mobile devices
|
||||
if os == "Android" || os == "iOS" {
|
||||
device_type = DeviceType::Mobile;
|
||||
}
|
||||
|
||||
// Handle iPads
|
||||
if model.contains("iPad") {
|
||||
device_type = DeviceType::Tablet;
|
||||
}
|
||||
|
||||
return Self {
|
||||
name: Some(name.to_owned()),
|
||||
version: Some(version.to_owned()),
|
||||
os: Some(os.to_owned()),
|
||||
os_version: os_version.map(std::borrow::ToOwned::to_owned),
|
||||
model: Some(model.to_owned()),
|
||||
device_type,
|
||||
raw: user_agent,
|
||||
};
|
||||
}
|
||||
|
||||
let mut model = None;
|
||||
@@ -205,11 +204,11 @@ impl UserAgent {
|
||||
}
|
||||
|
||||
// Special handling for Electron applications e.g. Element Desktop
|
||||
if user_agent.contains("Electron/") {
|
||||
if let Some(app) = UserAgent::parse_electron(&user_agent) {
|
||||
result.name = app.0;
|
||||
result.version = app.1;
|
||||
}
|
||||
if user_agent.contains("Electron/")
|
||||
&& let Some(app) = UserAgent::parse_electron(&user_agent)
|
||||
{
|
||||
result.name = app.0;
|
||||
result.version = app.1;
|
||||
}
|
||||
|
||||
Self {
|
||||
|
||||
@@ -223,17 +223,17 @@ impl UserRegistrationToken {
|
||||
}
|
||||
|
||||
// Check if expired
|
||||
if let Some(expires_at) = self.expires_at {
|
||||
if now >= expires_at {
|
||||
return false;
|
||||
}
|
||||
if let Some(expires_at) = self.expires_at
|
||||
&& now >= expires_at
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if usage limit exceeded
|
||||
if let Some(usage_limit) = self.usage_limit {
|
||||
if self.times_used >= usage_limit {
|
||||
return false;
|
||||
}
|
||||
if let Some(usage_limit) = self.usage_limit
|
||||
&& self.times_used >= usage_limit
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -187,10 +187,10 @@ where
|
||||
};
|
||||
|
||||
// If there is a user for this session, check that it is not locked
|
||||
if let Some(user) = &user {
|
||||
if !user.is_valid() {
|
||||
return Err(Rejection::UserLocked);
|
||||
}
|
||||
if let Some(user) = &user
|
||||
&& !user.is_valid()
|
||||
{
|
||||
return Err(Rejection::UserLocked);
|
||||
}
|
||||
|
||||
if !session.is_valid() {
|
||||
|
||||
@@ -8,8 +8,7 @@ use anyhow::Context as _;
|
||||
use async_graphql::{Context, Description, Enum, ID, Object};
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_storage::{oauth2::OAuth2ClientRepository, user::BrowserSessionRepository};
|
||||
use oauth2_types::{oidc::ApplicationType, scope::Scope};
|
||||
use ulid::Ulid;
|
||||
use oauth2_types::oidc::ApplicationType;
|
||||
use url::Url;
|
||||
|
||||
use super::{BrowserSession, NodeType, SessionState, User, UserAgent};
|
||||
@@ -200,33 +199,3 @@ impl OAuth2Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An OAuth 2.0 consent represents the scope a user consented to grant to a
|
||||
/// client.
|
||||
#[derive(Description)]
|
||||
pub struct OAuth2Consent {
|
||||
scope: Scope,
|
||||
client_id: Ulid,
|
||||
}
|
||||
|
||||
#[Object(use_type_description)]
|
||||
impl OAuth2Consent {
|
||||
/// Scope consented by the user for this client.
|
||||
pub async fn scope(&self) -> String {
|
||||
self.scope.to_string()
|
||||
}
|
||||
|
||||
/// OAuth 2.0 client for which the user granted access.
|
||||
pub async fn client(&self, ctx: &Context<'_>) -> Result<OAuth2Client, async_graphql::Error> {
|
||||
let state = ctx.state();
|
||||
let mut repo = state.repository().await?;
|
||||
let client = repo
|
||||
.oauth2_client()
|
||||
.lookup(self.client_id)
|
||||
.await?
|
||||
.context("Could not load client")?;
|
||||
repo.cancel().await?;
|
||||
|
||||
Ok(OAuth2Client(client))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ async fn test_oauth2_admin(pool: PgPool) {
|
||||
}
|
||||
|
||||
/// Test that we can query the GraphQL endpoint with a token from a
|
||||
/// client_credentials grant.
|
||||
/// `client_credentials` grant.
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_oauth2_client_credentials(pool: PgPool) {
|
||||
setup();
|
||||
|
||||
@@ -476,13 +476,13 @@ fn recover_error(
|
||||
) -> axum::response::Response {
|
||||
// Error responses should have an ErrorContext attached to them
|
||||
let ext = response.extensions().get::<ErrorContext>();
|
||||
if let Some(ctx) = ext {
|
||||
if let Ok(res) = templates.render_error(ctx) {
|
||||
let (mut parts, _original_body) = response.into_parts();
|
||||
parts.headers.remove(CONTENT_TYPE);
|
||||
parts.headers.remove(CONTENT_LENGTH);
|
||||
return (parts, Html(res)).into_response();
|
||||
}
|
||||
if let Some(ctx) = ext
|
||||
&& let Ok(res) = templates.render_error(ctx)
|
||||
{
|
||||
let (mut parts, _original_body) = response.into_parts();
|
||||
parts.headers.remove(CONTENT_TYPE);
|
||||
parts.headers.remove(CONTENT_LENGTH);
|
||||
return (parts, Html(res)).into_response();
|
||||
}
|
||||
|
||||
response
|
||||
|
||||
@@ -288,10 +288,10 @@ pub(crate) async fn post(
|
||||
|
||||
let token = &form.token;
|
||||
let token_type = TokenType::check(token)?;
|
||||
if let Some(hint) = form.token_type_hint {
|
||||
if token_type != hint {
|
||||
return Err(RouteError::UnexpectedTokenType);
|
||||
}
|
||||
if let Some(hint) = form.token_type_hint
|
||||
&& token_type != hint
|
||||
{
|
||||
return Err(RouteError::UnexpectedTokenType);
|
||||
}
|
||||
|
||||
// Not all device IDs can be encoded as scope. On OAuth 2.0 sessions, we
|
||||
|
||||
@@ -242,34 +242,34 @@ pub(crate) async fn post(
|
||||
|
||||
// Some extra validation that is hard to do in OPA and not done by the
|
||||
// `validate` method either
|
||||
if let Some(client_uri) = &metadata.client_uri {
|
||||
if localised_url_has_public_suffix(client_uri) {
|
||||
return Err(RouteError::UrlIsPublicSuffix("client_uri"));
|
||||
}
|
||||
if let Some(client_uri) = &metadata.client_uri
|
||||
&& localised_url_has_public_suffix(client_uri)
|
||||
{
|
||||
return Err(RouteError::UrlIsPublicSuffix("client_uri"));
|
||||
}
|
||||
|
||||
if let Some(logo_uri) = &metadata.logo_uri {
|
||||
if localised_url_has_public_suffix(logo_uri) {
|
||||
return Err(RouteError::UrlIsPublicSuffix("logo_uri"));
|
||||
}
|
||||
if let Some(logo_uri) = &metadata.logo_uri
|
||||
&& localised_url_has_public_suffix(logo_uri)
|
||||
{
|
||||
return Err(RouteError::UrlIsPublicSuffix("logo_uri"));
|
||||
}
|
||||
|
||||
if let Some(policy_uri) = &metadata.policy_uri {
|
||||
if localised_url_has_public_suffix(policy_uri) {
|
||||
return Err(RouteError::UrlIsPublicSuffix("policy_uri"));
|
||||
}
|
||||
if let Some(policy_uri) = &metadata.policy_uri
|
||||
&& localised_url_has_public_suffix(policy_uri)
|
||||
{
|
||||
return Err(RouteError::UrlIsPublicSuffix("policy_uri"));
|
||||
}
|
||||
|
||||
if let Some(tos_uri) = &metadata.tos_uri {
|
||||
if localised_url_has_public_suffix(tos_uri) {
|
||||
return Err(RouteError::UrlIsPublicSuffix("tos_uri"));
|
||||
}
|
||||
if let Some(tos_uri) = &metadata.tos_uri
|
||||
&& localised_url_has_public_suffix(tos_uri)
|
||||
{
|
||||
return Err(RouteError::UrlIsPublicSuffix("tos_uri"));
|
||||
}
|
||||
|
||||
if let Some(initiate_login_uri) = &metadata.initiate_login_uri {
|
||||
if host_is_public_suffix(initiate_login_uri) {
|
||||
return Err(RouteError::UrlIsPublicSuffix("initiate_login_uri"));
|
||||
}
|
||||
if let Some(initiate_login_uri) = &metadata.initiate_login_uri
|
||||
&& host_is_public_suffix(initiate_login_uri)
|
||||
{
|
||||
return Err(RouteError::UrlIsPublicSuffix("initiate_login_uri"));
|
||||
}
|
||||
|
||||
for redirect_uri in metadata.redirect_uris() {
|
||||
|
||||
@@ -93,17 +93,15 @@ pub(crate) async fn get(
|
||||
|
||||
// Forward the raw login hint upstream for the provider to handle however it
|
||||
// sees fit
|
||||
if provider.forward_login_hint {
|
||||
if let Some(PostAuthAction::ContinueAuthorizationGrant { id }) = &query.post_auth_action {
|
||||
if let Some(login_hint) = repo
|
||||
.oauth2_authorization_grant()
|
||||
.lookup(*id)
|
||||
.await?
|
||||
.and_then(|grant| grant.login_hint)
|
||||
{
|
||||
data = data.with_login_hint(login_hint);
|
||||
}
|
||||
}
|
||||
if provider.forward_login_hint
|
||||
&& let Some(PostAuthAction::ContinueAuthorizationGrant { id }) = &query.post_auth_action
|
||||
&& let Some(login_hint) = repo
|
||||
.oauth2_authorization_grant()
|
||||
.lookup(*id)
|
||||
.await?
|
||||
.and_then(|grant| grant.login_hint)
|
||||
{
|
||||
data = data.with_login_hint(login_hint);
|
||||
}
|
||||
|
||||
let data = if let Some(methods) = lazy_metadata.pkce_methods().await? {
|
||||
|
||||
@@ -34,14 +34,14 @@ pub(crate) async fn post(
|
||||
|
||||
if let Some(session_id) = session_info.current_session_id() {
|
||||
let maybe_session = repo.browser_session().lookup(session_id).await?;
|
||||
if let Some(session) = maybe_session {
|
||||
if session.finished_at.is_none() {
|
||||
activity_tracker
|
||||
.record_browser_session(&clock, &session)
|
||||
.await;
|
||||
if let Some(session) = maybe_session
|
||||
&& session.finished_at.is_none()
|
||||
{
|
||||
activity_tracker
|
||||
.record_browser_session(&clock, &session)
|
||||
.await;
|
||||
|
||||
repo.browser_session().finish(&clock, session).await?;
|
||||
}
|
||||
repo.browser_session().finish(&clock, session).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,36 +110,36 @@ fn find_in_call<'a>(
|
||||
call: &'a Spanned<Call<'a>>,
|
||||
) -> Result<(), minijinja::Error> {
|
||||
let span = call.span();
|
||||
if let Expr::Var(var_) = &call.expr {
|
||||
if var_.id == context.func() {
|
||||
let key = call
|
||||
.args
|
||||
.first()
|
||||
.and_then(as_const)
|
||||
.and_then(|const_| const_.value.as_str())
|
||||
.ok_or(minijinja::Error::new(
|
||||
ErrorKind::UndefinedError,
|
||||
"t() first argument must be a string literal",
|
||||
))?;
|
||||
if let Expr::Var(var_) = &call.expr
|
||||
&& var_.id == context.func()
|
||||
{
|
||||
let key = call
|
||||
.args
|
||||
.first()
|
||||
.and_then(as_const)
|
||||
.and_then(|const_| const_.value.as_str())
|
||||
.ok_or(minijinja::Error::new(
|
||||
ErrorKind::UndefinedError,
|
||||
"t() first argument must be a string literal",
|
||||
))?;
|
||||
|
||||
let has_count = call
|
||||
.args
|
||||
.iter()
|
||||
.any(|arg| matches!(arg, CallArg::Kwarg("count", _)));
|
||||
let has_count = call
|
||||
.args
|
||||
.iter()
|
||||
.any(|arg| matches!(arg, CallArg::Kwarg("count", _)));
|
||||
|
||||
let key = Key::new(
|
||||
if has_count {
|
||||
crate::key::Kind::Plural
|
||||
} else {
|
||||
crate::key::Kind::Message
|
||||
},
|
||||
key.to_owned(),
|
||||
);
|
||||
let key = Key::new(
|
||||
if has_count {
|
||||
crate::key::Kind::Plural
|
||||
} else {
|
||||
crate::key::Kind::Message
|
||||
},
|
||||
key.to_owned(),
|
||||
);
|
||||
|
||||
let key = context.set_key_location(key, span);
|
||||
let key = context.set_key_location(key, span);
|
||||
|
||||
context.record(key);
|
||||
}
|
||||
context.record(key);
|
||||
}
|
||||
|
||||
find_in_expr(context, &call.expr)?;
|
||||
|
||||
@@ -72,6 +72,7 @@ pub(crate) use sprintf;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error(transparent)]
|
||||
#[allow(dead_code)]
|
||||
enum Error {
|
||||
Format(#[from] self::formatter::FormatError),
|
||||
Parse(Box<self::parser::Error>),
|
||||
|
||||
@@ -279,11 +279,11 @@ where
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
||||
if let Poll::Ready(()) = this.cancellation_future.poll(cx) {
|
||||
if !*this.did_start_shutdown {
|
||||
*this.did_start_shutdown = true;
|
||||
this.connection.as_mut().graceful_shutdown();
|
||||
}
|
||||
if let Poll::Ready(()) = this.cancellation_future.poll(cx)
|
||||
&& !*this.did_start_shutdown
|
||||
{
|
||||
*this.did_start_shutdown = true;
|
||||
this.connection.as_mut().graceful_shutdown();
|
||||
}
|
||||
|
||||
this.connection.poll(cx)
|
||||
|
||||
@@ -577,7 +577,7 @@ pub struct ProviderMetadata {
|
||||
pub require_request_uri_registration: Option<bool>,
|
||||
|
||||
/// Indicates where authorization request needs to be protected as [Request
|
||||
/// Object] and provided through either request or request_uri parameter.
|
||||
/// Object] and provided through either request or `request_uri` parameter.
|
||||
///
|
||||
/// Defaults to `false`.
|
||||
///
|
||||
@@ -680,10 +680,10 @@ impl ProviderMetadata {
|
||||
validate_url("registration_endpoint", url, ExtraUrlRestrictions::None)?;
|
||||
}
|
||||
|
||||
if let Some(scopes) = &metadata.scopes_supported {
|
||||
if !scopes.iter().any(|s| s == "openid") {
|
||||
return Err(ProviderMetadataVerificationError::ScopesMissingOpenid);
|
||||
}
|
||||
if let Some(scopes) = &metadata.scopes_supported
|
||||
&& !scopes.iter().any(|s| s == "openid")
|
||||
{
|
||||
return Err(ProviderMetadataVerificationError::ScopesMissingOpenid);
|
||||
}
|
||||
|
||||
validate_signing_alg_values_supported(
|
||||
|
||||
@@ -911,7 +911,8 @@ pub struct ClientRegistrationResponse {
|
||||
#[serde_as(as = "Option<TimestampSeconds<i64>>")]
|
||||
pub client_id_issued_at: Option<DateTime<Utc>>,
|
||||
|
||||
/// Time at which the client_secret will expire or 0 if it will not expire.
|
||||
/// Time at which the `client_secret` will expire or 0 if it will not
|
||||
/// expire.
|
||||
///
|
||||
/// Required if `client_secret` is issued.
|
||||
#[serde(default)]
|
||||
|
||||
@@ -74,7 +74,7 @@ fn keystore(alg: &JsonWebSignatureAlg) -> Keystore {
|
||||
}
|
||||
|
||||
/// Generate an ID token.
|
||||
fn id_token(issuer: &str) -> (IdToken, PublicJsonWebKeySet) {
|
||||
fn id_token(issuer: &str) -> (IdToken<'_>, PublicJsonWebKeySet) {
|
||||
let signing_alg = ID_TOKEN_SIGNING_ALG;
|
||||
|
||||
let keystore = keystore(&signing_alg);
|
||||
|
||||
@@ -34,7 +34,7 @@ fn id_token(
|
||||
issuer: &str,
|
||||
flag: Option<IdTokenFlag>,
|
||||
auth_time: Option<DateTime<Utc>>,
|
||||
) -> (IdToken, PublicJsonWebKeySet) {
|
||||
) -> (IdToken<'_>, PublicJsonWebKeySet) {
|
||||
let signing_alg = ID_TOKEN_SIGNING_ALG;
|
||||
|
||||
let keystore = keystore(&signing_alg);
|
||||
|
||||
@@ -397,7 +397,7 @@ impl Policy {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Evaluate the 'client_registration' entrypoint.
|
||||
/// Evaluate the `client_registration` entrypoint.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -419,7 +419,7 @@ impl Policy {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Evaluate the 'authorization_grant' entrypoint.
|
||||
/// Evaluate the `authorization_grant` entrypoint.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
||||
@@ -696,7 +696,7 @@ mod tests {
|
||||
// List all logins
|
||||
let logins = repo.compat_sso_login().list(all, pagination).await.unwrap();
|
||||
assert!(!logins.has_next_page);
|
||||
assert_eq!(logins.edges, &[login.clone()]);
|
||||
assert_eq!(logins.edges, vec![login.clone()]);
|
||||
|
||||
// List the logins for the user
|
||||
let logins = repo
|
||||
@@ -705,7 +705,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!logins.has_next_page);
|
||||
assert_eq!(logins.edges, &[login.clone()]);
|
||||
assert_eq!(logins.edges, vec![login.clone()]);
|
||||
|
||||
// List only the pending logins for the user
|
||||
let logins = repo
|
||||
|
||||
@@ -524,7 +524,7 @@ mod tests {
|
||||
&mut rng,
|
||||
&clock,
|
||||
"alice".to_owned(),
|
||||
Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
||||
Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||
Some("Mozilla/5.0".to_owned()),
|
||||
Some(serde_json::json!({"action": "continue_compat_sso_login", "id": "01FSHN9AG0MKGTBNZ16RDR3PVY"})),
|
||||
)
|
||||
@@ -534,7 +534,7 @@ mod tests {
|
||||
assert_eq!(registration.user_agent, Some("Mozilla/5.0".to_owned()));
|
||||
assert_eq!(
|
||||
registration.ip_address,
|
||||
Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
|
||||
Some(IpAddr::V4(Ipv4Addr::LOCALHOST))
|
||||
);
|
||||
assert_eq!(
|
||||
registration.post_auth_action,
|
||||
|
||||
@@ -38,7 +38,7 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
|
||||
/// * `response_mode`: The response mode the client requested
|
||||
/// * `response_type_id_token`: Whether the `id_token` `response_type` was
|
||||
/// requested
|
||||
/// * `login_hint`: The login_hint the client sent, if set
|
||||
/// * `login_hint`: The `login_hint` the client sent, if set
|
||||
/// * `locale`: The locale the detected when the user asked for the
|
||||
/// authorization grant
|
||||
///
|
||||
|
||||
@@ -24,7 +24,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
/// The error type returned by the repository
|
||||
type Error;
|
||||
|
||||
/// Lookup an OAuth2 client by its ID
|
||||
/// Lookup an OAuth client by its ID
|
||||
///
|
||||
/// Returns `None` if the client does not exist
|
||||
///
|
||||
@@ -37,7 +37,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
/// Returns [`Self::Error`] if the underlying repository fails
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<Client>, Self::Error>;
|
||||
|
||||
/// Find an OAuth2 client by its client ID
|
||||
/// Find an OAuth client by its client ID
|
||||
async fn find_by_client_id(&mut self, client_id: &str) -> Result<Option<Client>, Self::Error> {
|
||||
let Ok(id) = client_id.parse() else {
|
||||
return Ok(None);
|
||||
@@ -45,7 +45,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
self.lookup(id).await
|
||||
}
|
||||
|
||||
/// Find an OAuth2 client by its metadata digest
|
||||
/// Find an OAuth client by its metadata digest
|
||||
///
|
||||
/// Returns `None` if the client does not exist
|
||||
///
|
||||
@@ -62,7 +62,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
digest: &str,
|
||||
) -> Result<Option<Client>, Self::Error>;
|
||||
|
||||
/// Load a batch of OAuth2 clients by their IDs
|
||||
/// Load a batch of OAuth clients by their IDs
|
||||
///
|
||||
/// Returns a map of client IDs to clients. If a client does not exist, it
|
||||
/// is not present in the map.
|
||||
@@ -79,7 +79,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
ids: BTreeSet<Ulid>,
|
||||
) -> Result<BTreeMap<Ulid, Client>, Self::Error>;
|
||||
|
||||
/// Add a new OAuth2 client
|
||||
/// Add a new OAuth client
|
||||
///
|
||||
/// Returns the client that was added
|
||||
///
|
||||
|
||||
@@ -250,7 +250,8 @@ pub async fn synapse_config_check_against_mas_config(
|
||||
///
|
||||
/// - If there is some database connection error, or the given database is not a
|
||||
/// Synapse database.
|
||||
/// - If the OAuth2 section of the MAS configuration could not be parsed.
|
||||
/// - If the Upstream OAuth section of the MAS configuration could not be
|
||||
/// parsed.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn synapse_database_check(
|
||||
synapse_connection: &mut PgConnection,
|
||||
|
||||
@@ -120,14 +120,14 @@ impl Config {
|
||||
pub fn all_oidc_providers(&self) -> BTreeMap<String, OidcProvider> {
|
||||
let mut out = BTreeMap::new();
|
||||
|
||||
if let Some(provider) = &self.oidc_config {
|
||||
if provider.has_required_fields() {
|
||||
let mut provider = provider.clone();
|
||||
// The legacy configuration has an implied IdP ID of `oidc`.
|
||||
let idp_id = provider.idp_id.take().unwrap_or("oidc".to_owned());
|
||||
provider.idp_id = Some(idp_id.clone());
|
||||
out.insert(idp_id, provider);
|
||||
}
|
||||
if let Some(provider) = &self.oidc_config
|
||||
&& provider.has_required_fields()
|
||||
{
|
||||
let mut provider = provider.clone();
|
||||
// The legacy configuration has an implied IdP ID of `oidc`.
|
||||
let idp_id = provider.idp_id.take().unwrap_or("oidc".to_owned());
|
||||
provider.idp_id = Some(idp_id.clone());
|
||||
out.insert(idp_id, provider);
|
||||
}
|
||||
|
||||
for provider in &self.oidc_providers {
|
||||
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
|
||||
/// Job to provision a user on the Matrix homeserver.
|
||||
/// This works by doing a PUT request to the
|
||||
/// /_synapse/admin/v2/users/{user_id} endpoint.
|
||||
/// `/_synapse/admin/v2/users/{user_id}` endpoint.
|
||||
#[async_trait]
|
||||
impl RunnableJob for ProvisionUserJob {
|
||||
#[tracing::instrument(
|
||||
|
||||
@@ -1637,7 +1637,7 @@ impl TemplateContext for DeviceConsentContext {
|
||||
device_code: Alphanumeric.sample_string(rng, 32),
|
||||
created_at: now - Duration::try_minutes(5).unwrap(),
|
||||
expires_at: now + Duration::try_minutes(25).unwrap(),
|
||||
ip_address: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
||||
ip_address: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||
user_agent: Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36".to_owned()),
|
||||
};
|
||||
Self { grant, client }
|
||||
|
||||
@@ -328,7 +328,7 @@ register_templates! {
|
||||
/// Render the Swagger API reference
|
||||
pub fn render_swagger(ApiDocContext) { "swagger/doc.html" }
|
||||
|
||||
/// Render the Swagger OAuth2 callback page
|
||||
/// Render the Swagger OAuth callback page
|
||||
pub fn render_swagger_callback(ApiDocContext) { "swagger/oauth2-redirect.html" }
|
||||
|
||||
/// Render the login page
|
||||
@@ -382,7 +382,7 @@ register_templates! {
|
||||
/// Render the account recovery disabled page
|
||||
pub fn render_recovery_disabled(WithLanguage<EmptyContext>) { "pages/recovery/disabled.html" }
|
||||
|
||||
/// Render the form used by the form_post response mode
|
||||
/// Render the form used by the `form_post` response mode
|
||||
pub fn render_form_post<T: Serialize>(WithLanguage<FormPostContext<T>>) { "form_post.html" }
|
||||
|
||||
/// Render the HTML error page
|
||||
|
||||
@@ -24,8 +24,8 @@ ignore = [
|
||||
[licenses]
|
||||
version = 2
|
||||
allow = [
|
||||
"LicenseRef-Element-Commercial",
|
||||
"0BSD",
|
||||
"AGPL-3.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"Apache-2.0",
|
||||
"BSD-2-Clause",
|
||||
@@ -80,9 +80,6 @@ skip = [
|
||||
{ name = "rustix", version = "0.38.44" },
|
||||
{ name = "linux-raw-sys", version = "0.9.4" },
|
||||
|
||||
# This is a compatibility version of webpki-roots that depends on the 1.0 version
|
||||
{ name = "webpki-roots", version = "0.26.11" },
|
||||
|
||||
# We are still mainly using rand 0.8
|
||||
{ name = "rand", version = "0.8.5" },
|
||||
{ name = "rand_chacha", version = "0.3.1" },
|
||||
@@ -103,6 +100,6 @@ unknown-git = "warn"
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
|
||||
allow-git = [
|
||||
# https://github.com/open-telemetry/opentelemetry-rust/pull/3076
|
||||
"https://github.com/sandhose/opentelemetry-rust",
|
||||
# https://github.com/open-telemetry/opentelemetry-rust/pull/3076
|
||||
"https://github.com/sandhose/opentelemetry-rust",
|
||||
]
|
||||
|
||||
@@ -2155,7 +2155,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"on_backchannel_logout": {
|
||||
"description": "What to do when receiving an OIDC Backchannel logout request.\n\nDefaults to \"do_nothing\".",
|
||||
"description": "What to do when receiving an OIDC Backchannel logout request.\n\nDefaults to `do_nothing`.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/OnBackchannelLogout"
|
||||
|
||||
98
frontend/package-lock.json
generated
98
frontend/package-lock.json
generated
@@ -24,7 +24,7 @@
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-i18next": "^15.6.1",
|
||||
"swagger-ui-dist": "^5.27.0",
|
||||
"swagger-ui-dist": "^5.27.1",
|
||||
"valibot": "^1.1.0",
|
||||
"vaul": "^1.1.2"
|
||||
},
|
||||
@@ -66,7 +66,7 @@
|
||||
"storybook": "^9.0.1",
|
||||
"storybook-react-i18next": "4.0.11",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "6.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-graphql-codegen": "^3.6.1",
|
||||
@@ -3248,6 +3248,23 @@
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/external-editor": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.0.tgz",
|
||||
"integrity": "sha512-5v3YXc5ZMfL6OJqXPrX9csb4l7NlQA2doO1yynUjpUChT9hg4JcuBVP0RbsEJ/3SL/sxWEyFjT2W69ZhtoBWqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chardet": "^2.1.0",
|
||||
"iconv-lite": "^0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/figures": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz",
|
||||
@@ -6907,9 +6924,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chardet": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
|
||||
"integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -7854,34 +7871,6 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chardet": "^0.7.0",
|
||||
"iconv-lite": "^0.4.24",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor/node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-fifo": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||
@@ -8980,17 +8969,17 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/inquirer": {
|
||||
"version": "8.2.6",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
|
||||
"integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
|
||||
"version": "8.2.7",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz",
|
||||
"integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@inquirer/external-editor": "^1.0.0",
|
||||
"ansi-escapes": "^4.2.1",
|
||||
"chalk": "^4.1.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-width": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^3.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mute-stream": "0.0.8",
|
||||
@@ -10281,16 +10270,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/outvariant": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz",
|
||||
@@ -12355,9 +12334,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "5.27.0",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.0.tgz",
|
||||
"integrity": "sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==",
|
||||
"version": "5.27.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.1.tgz",
|
||||
"integrity": "sha512-oGtpYO3lnoaqyGtlJalvryl7TwzgRuxpOVWqEHx8af0YXI+Kt+4jMpLdgMtMcmWmuQ0QTCHLKExwrBFMSxvAUA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scarf/scarf": "=1.4.0"
|
||||
@@ -12714,19 +12693,6 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -12875,9 +12841,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-i18next": "^15.6.1",
|
||||
"swagger-ui-dist": "^5.27.0",
|
||||
"swagger-ui-dist": "^5.27.1",
|
||||
"valibot": "^1.1.0",
|
||||
"vaul": "^1.1.2"
|
||||
},
|
||||
@@ -76,7 +76,7 @@
|
||||
"storybook": "^9.0.1",
|
||||
"storybook-react-i18next": "4.0.11",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "6.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-graphql-codegen": "^3.6.1",
|
||||
|
||||
Reference in New Issue
Block a user