mirror of
https://github.com/adriankumpf/tesla_auth.git
synced 2026-02-27 09:54:03 +08:00
Replace JS template interpolation with DOM APIs
Use serde_json::to_string() to safely encode Rust strings as JS string literals and DOM element creation (.textContent, .value) on the JS side to insert into the page.
This commit is contained in:
Generated
-1
@@ -2852,7 +2852,6 @@ dependencies = [
|
|||||||
"muda",
|
"muda",
|
||||||
"oauth2",
|
"oauth2",
|
||||||
"reqwest 0.13.2",
|
"reqwest 0.13.2",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"static_vcruntime",
|
"static_vcruntime",
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ reqwest = { version = "0.13.2", default-features = false, features = [
|
|||||||
"json",
|
"json",
|
||||||
"rustls",
|
"rustls",
|
||||||
] }
|
] }
|
||||||
serde = { version = "1.0.228", default-features = false, features = ["derive"] }
|
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
simple_logger = { version = "5.2.0", default-features = false, features = [
|
simple_logger = { version = "5.2.0", default-features = false, features = [
|
||||||
"stderr",
|
"stderr",
|
||||||
|
|||||||
+58
-29
@@ -168,12 +168,16 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Event::UserEvent(UserEvent::Failure(error)) => {
|
Event::UserEvent(UserEvent::Failure(error)) => {
|
||||||
log::error!("{error}");
|
log::error!("{error}");
|
||||||
webview.evaluate_script(&render_error_view(error)).unwrap();
|
if let Err(e) = webview.evaluate_script(&render_error_view(error)) {
|
||||||
|
log::error!("Failed to render error view: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::UserEvent(UserEvent::Tokens(token)) => {
|
Event::UserEvent(UserEvent::Tokens(token)) => {
|
||||||
println!("{token}");
|
println!("{token}");
|
||||||
webview.evaluate_script(&render_tokens_view(token)).unwrap();
|
if let Err(e) = webview.evaluate_script(&render_tokens_view(token)) {
|
||||||
|
log::error!("Failed to render tokens view: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::UserEvent(UserEvent::LoginCanceled) => {
|
Event::UserEvent(UserEvent::LoginCanceled) => {
|
||||||
@@ -244,36 +248,61 @@ fn handle_redirect(url: &Url, client: auth::Client) -> UserEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode a string as a JSON string literal for safe JS interpolation.
|
||||||
|
#[expect(clippy::unwrap_used)] // serde_json string serialization is infallible
|
||||||
|
fn js_string(s: &str) -> String {
|
||||||
|
serde_json::to_string(s).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn render_error_view(error: anyhow::Error) -> String {
|
fn render_error_view(error: anyhow::Error) -> String {
|
||||||
r#"
|
let msg = js_string(&error.to_string());
|
||||||
const html = `
|
format!(
|
||||||
<h4 style="text-align: center;">An error occurred. Please try again ...</h4>
|
r#"(function() {{
|
||||||
<p style="text-align: center;color:red;margin-bottom:20px;">{msg}</p>
|
var target = document.querySelector("h1.h1");
|
||||||
`;
|
var h4 = document.createElement("h4");
|
||||||
document.querySelector("h1.h1").outerHTML = html;
|
h4.style.textAlign = "center";
|
||||||
"#
|
h4.textContent = "An error occurred. Please try again ...";
|
||||||
.replace("{msg}", &error.to_string())
|
var p = document.createElement("p");
|
||||||
|
p.style.cssText = "text-align:center;color:red;margin-bottom:20px";
|
||||||
|
p.textContent = {msg};
|
||||||
|
target.replaceWith(h4, p);
|
||||||
|
}})()"#
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_tokens_view(tokens: auth::Tokens) -> String {
|
fn render_tokens_view(tokens: auth::Tokens) -> String {
|
||||||
r#"
|
let access = js_string(tokens.access.secret());
|
||||||
const html = `
|
let refresh = js_string(tokens.refresh.secret());
|
||||||
<h4 style="text-align: center;">Access Token</h4>
|
let expires = js_string(&tokens.expires_in.to_string());
|
||||||
<textarea readonly onclick="this.setSelectionRange(0, this.value.length)"
|
format!(
|
||||||
cols="100" rows="12" style="resize:none;padding:4px;font-size:0.9em;"
|
r#"(function() {{
|
||||||
>{access_token}</textarea>
|
var target = document.querySelector("h1.h1");
|
||||||
<h4 style="text-align: center;">Refresh Token</h4>
|
var frag = document.createDocumentFragment();
|
||||||
<textarea readonly onclick="this.setSelectionRange(0, this.value.length)"
|
|
||||||
cols="100" rows="12" style="resize:none;padding:4px;font-size:0.9em;"
|
|
||||||
>{refresh_token}</textarea>
|
|
||||||
<small style="margin-top:12px;margin-bottom:20px;text-align:center;color:seagreen;">
|
|
||||||
Valid for {expires_in}
|
|
||||||
</small>
|
|
||||||
`;
|
|
||||||
|
|
||||||
document.querySelector("h1.h1").outerHTML = html;
|
function addToken(label, value) {{
|
||||||
"#
|
var h4 = document.createElement("h4");
|
||||||
.replace("{access_token}", tokens.access.secret())
|
h4.style.textAlign = "center";
|
||||||
.replace("{refresh_token}", tokens.refresh.secret())
|
h4.textContent = label;
|
||||||
.replace("{expires_in}", &format!("{}", tokens.expires_in))
|
frag.appendChild(h4);
|
||||||
|
var ta = document.createElement("textarea");
|
||||||
|
ta.readOnly = true;
|
||||||
|
ta.cols = 100;
|
||||||
|
ta.rows = 12;
|
||||||
|
ta.style.cssText = "resize:none;padding:4px;font-size:0.9em";
|
||||||
|
ta.value = value;
|
||||||
|
ta.addEventListener("click", function() {{ this.setSelectionRange(0, this.value.length); }});
|
||||||
|
frag.appendChild(ta);
|
||||||
|
}}
|
||||||
|
|
||||||
|
addToken("Access Token", {access});
|
||||||
|
addToken("Refresh Token", {refresh});
|
||||||
|
|
||||||
|
var small = document.createElement("small");
|
||||||
|
small.style.cssText = "margin-top:12px;margin-bottom:20px;text-align:center;color:seagreen";
|
||||||
|
small.textContent = "Valid for " + {expires};
|
||||||
|
frag.appendChild(small);
|
||||||
|
|
||||||
|
target.replaceWith(frag);
|
||||||
|
}})()"#
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user