mirror of
https://github.com/leptos-rs/leptos
synced 2025-02-03 07:23:26 +00:00
fix: include missing nonces on streaming script tags and on leptos_meta
components (closes #3482) (#3485)
This commit is contained in:
parent
a9ce608433
commit
293149eeb2
10 changed files with 103 additions and 11 deletions
integrations
leptos/src
meta
tachys/src
|
@ -18,7 +18,7 @@ hydration_context = { workspace = true }
|
|||
leptos = { workspace = true, features = ["nonce", "ssr"] }
|
||||
leptos_integration_utils = { workspace = true }
|
||||
leptos_macro = { workspace = true, features = ["actix"] }
|
||||
leptos_meta = { workspace = true }
|
||||
leptos_meta = { workspace = true, features = ["nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
server_fn = { workspace = true, features = ["actix"] }
|
||||
serde_json = "1.0"
|
||||
|
|
|
@ -19,7 +19,7 @@ futures = "0.3.31"
|
|||
leptos = { workspace = true, features = ["nonce", "ssr"] }
|
||||
server_fn = { workspace = true, features = ["axum-no-default"] }
|
||||
leptos_macro = { workspace = true, features = ["axum"] }
|
||||
leptos_meta = { workspace = true, features = ["ssr"] }
|
||||
leptos_meta = { workspace = true, features = ["ssr", "nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
leptos_integration_utils = { workspace = true }
|
||||
once_cell = "1"
|
||||
|
|
|
@ -51,6 +51,13 @@ use tachys::html::attribute::AttributeValue;
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Nonce(pub(crate) Arc<str>);
|
||||
|
||||
impl Nonce {
|
||||
/// Returns a reference to the inner reference-counted string slice representing the nonce.
|
||||
pub fn as_inner(&self) -> &Arc<str> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Nonce {
|
||||
type Target = str;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use reactive_graph::{
|
|||
traits::{Dispose, Get, Read, Track, With},
|
||||
};
|
||||
use slotmap::{DefaultKey, SlotMap};
|
||||
use std::sync::Arc;
|
||||
use tachys::{
|
||||
either::Either,
|
||||
html::attribute::Attribute,
|
||||
|
@ -132,6 +133,18 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn nonce_or_not() -> Option<Arc<str>> {
|
||||
#[cfg(feature = "nonce")]
|
||||
{
|
||||
use crate::nonce::Nonce;
|
||||
use_context::<Nonce>().map(|n| n.0)
|
||||
}
|
||||
#[cfg(not(feature = "nonce"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SuspenseBoundary<const TRANSITION: bool, Fal, Chil> {
|
||||
pub id: SerializedDataId,
|
||||
pub none_pending: ArcMemo<bool>,
|
||||
|
@ -379,7 +392,12 @@ where
|
|||
&mut fallback_position,
|
||||
mark_branches,
|
||||
);
|
||||
buf.push_async_out_of_order(fut, position, mark_branches);
|
||||
buf.push_async_out_of_order_with_nonce(
|
||||
fut,
|
||||
position,
|
||||
mark_branches,
|
||||
nonce_or_not(),
|
||||
);
|
||||
} else {
|
||||
buf.push_async({
|
||||
let mut position = *position;
|
||||
|
|
|
@ -26,6 +26,7 @@ features = ["HtmlLinkElement", "HtmlMetaElement", "HtmlTitleElement"]
|
|||
default = []
|
||||
ssr = []
|
||||
tracing = ["dep:tracing"]
|
||||
nonce = ["leptos/nonce"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
|
|
@ -47,6 +47,7 @@ use leptos::{
|
|||
attr::NextAttribute,
|
||||
component,
|
||||
logging::debug_warn,
|
||||
oco::Oco,
|
||||
reactive::owner::{provide_context, use_context},
|
||||
tachys::{
|
||||
dom::document,
|
||||
|
@ -566,3 +567,25 @@ impl RenderHtml for MetaTagsView {
|
|||
) -> Self::State {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait OrDefaultNonce {
|
||||
fn or_default_nonce(self) -> Option<Oco<'static, str>>;
|
||||
}
|
||||
|
||||
impl OrDefaultNonce for Option<Oco<'static, str>> {
|
||||
fn or_default_nonce(self) -> Option<Oco<'static, str>> {
|
||||
#[cfg(feature = "nonce")]
|
||||
{
|
||||
use leptos::nonce::use_nonce;
|
||||
|
||||
match self {
|
||||
Some(nonce) => Some(nonce),
|
||||
None => use_nonce().map(|n| Arc::clone(n.as_inner()).into()),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nonce"))]
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::register;
|
||||
use crate::{register, OrDefaultNonce};
|
||||
use leptos::{
|
||||
component, oco::Oco, prelude::*, tachys::html::element::script, IntoView,
|
||||
};
|
||||
|
@ -74,7 +74,7 @@ pub fn Script(
|
|||
.fetchpriority(fetchpriority)
|
||||
.integrity(integrity)
|
||||
.nomodule(nomodule)
|
||||
.nonce(nonce)
|
||||
.nonce(nonce.or_default_nonce())
|
||||
.referrerpolicy(referrerpolicy)
|
||||
.src(src)
|
||||
.r#type(type_)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::register;
|
||||
use crate::{register, OrDefaultNonce};
|
||||
use leptos::{
|
||||
component, oco::Oco, prelude::*, tachys::html::element::style, IntoView,
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ pub fn Style(
|
|||
style()
|
||||
.id(id)
|
||||
.media(media)
|
||||
.nonce(nonce)
|
||||
.nonce(nonce.or_default_nonce())
|
||||
.title(title)
|
||||
.blocking(blocking)
|
||||
.child(children.map(|c| c())),
|
||||
|
|
|
@ -339,6 +339,12 @@ where
|
|||
&mut fallback_position,
|
||||
mark_branches,
|
||||
);
|
||||
|
||||
// TODO in 0.8: this should include a nonce
|
||||
// we do have access to nonces via context (because this is the `reactive_graph` module)
|
||||
// but unfortunately the Nonce type is defined in `leptos`, not in `tachys`
|
||||
//
|
||||
// missing it here only affects top-level Suspend, not Suspense components
|
||||
buf.push_async_out_of_order(
|
||||
fut,
|
||||
position,
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
|||
future::Future,
|
||||
mem,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
|
@ -161,6 +162,24 @@ impl StreamBuilder {
|
|||
mark_branches: bool,
|
||||
) where
|
||||
View: RenderHtml,
|
||||
{
|
||||
self.push_async_out_of_order_with_nonce(
|
||||
view,
|
||||
position,
|
||||
mark_branches,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
/// Injects an out-of-order chunk into the stream, using the given nonce for `<script>` tags.
|
||||
pub fn push_async_out_of_order_with_nonce<View>(
|
||||
&mut self,
|
||||
view: impl Future<Output = Option<View>> + Send + 'static,
|
||||
position: &mut Position,
|
||||
mark_branches: bool,
|
||||
nonce: Option<Arc<str>>,
|
||||
) where
|
||||
View: RenderHtml,
|
||||
{
|
||||
let id = self.clone_id();
|
||||
// copy so it's not updated by additional iterations
|
||||
|
@ -196,6 +215,7 @@ impl StreamBuilder {
|
|||
id,
|
||||
chunks,
|
||||
replace,
|
||||
nonce,
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
@ -234,6 +254,7 @@ pub struct OooChunk {
|
|||
id: String,
|
||||
chunks: VecDeque<StreamChunk>,
|
||||
replace: bool,
|
||||
nonce: Option<Arc<str>>,
|
||||
}
|
||||
|
||||
impl OooChunk {
|
||||
|
@ -247,11 +268,25 @@ impl OooChunk {
|
|||
|
||||
/// Pushes a closing `</template>` and update script into the buffer.
|
||||
pub fn push_end(replace: bool, id: &str, buf: &mut String) {
|
||||
Self::push_end_with_nonce(replace, id, buf, None);
|
||||
}
|
||||
|
||||
/// Pushes a closing `</template>` and update script with the given nonce into the buffer.
|
||||
pub fn push_end_with_nonce(
|
||||
replace: bool,
|
||||
id: &str,
|
||||
buf: &mut String,
|
||||
nonce: Option<&str>,
|
||||
) {
|
||||
buf.push_str("</template>");
|
||||
|
||||
// TODO nonce
|
||||
buf.push_str("<script");
|
||||
buf.push_str(r#">(function() { let id = ""#);
|
||||
if let Some(nonce) = nonce {
|
||||
buf.push_str("<script nonce=\"");
|
||||
buf.push_str(nonce);
|
||||
buf.push_str(r#"">(function() { let id = ""#);
|
||||
} else {
|
||||
buf.push_str(r#"<script>(function() { let id = ""#);
|
||||
}
|
||||
buf.push_str(id);
|
||||
buf.push_str(
|
||||
"\";let open = undefined;let close = undefined;let walker = \
|
||||
|
@ -324,6 +359,7 @@ impl Stream for StreamBuilder {
|
|||
id,
|
||||
chunks,
|
||||
replace,
|
||||
nonce,
|
||||
}) => {
|
||||
let opening = format!("<!--s-{id}o-->");
|
||||
let placeholder_at =
|
||||
|
@ -369,10 +405,11 @@ impl Stream for StreamBuilder {
|
|||
this.chunks.push_front(chunk);
|
||||
}
|
||||
}
|
||||
OooChunk::push_end(
|
||||
OooChunk::push_end_with_nonce(
|
||||
replace,
|
||||
&id,
|
||||
&mut this.sync_buf,
|
||||
nonce.as_deref(),
|
||||
);
|
||||
}
|
||||
self.poll_next(cx)
|
||||
|
|
Loading…
Reference in a new issue