mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 20:18:37 +00:00
fix: resolve P3 audit findings
This commit is contained in:
@@ -52,6 +52,7 @@ tokio-tungstenite = "0.29.0"
|
||||
futures-util = { version = "0.3.32", features = ["sink"] }
|
||||
rusqlite = { version = "0.40.1", features = ["bundled"] }
|
||||
chrono = "0.4.38"
|
||||
url = "2"
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
cocoa = "0.25"
|
||||
objc = "0.2.7"
|
||||
url = "2"
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
use rusqlite::{Connection, Result, params};
|
||||
use tokio::sync::Mutex;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
pub struct DbState {
|
||||
@@ -8,7 +8,7 @@ pub struct DbState {
|
||||
}
|
||||
|
||||
pub fn init_db(app_handle: &tauri::AppHandle) -> Result<Connection> {
|
||||
let app_dir = app_handle.path().app_data_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||
let app_dir = app_handle.path().app_data_dir().expect("Cannot get app data dir");
|
||||
if !app_dir.exists() {
|
||||
let _ = std::fs::create_dir_all(&app_dir);
|
||||
}
|
||||
|
||||
@@ -81,16 +81,11 @@ pub async fn start_server(
|
||||
.layer(cors)
|
||||
.with_state(state);
|
||||
|
||||
let mut listener = None;
|
||||
for port in EXTENSION_SERVER_PORT..=(EXTENSION_SERVER_PORT + 10) {
|
||||
if let Ok(l) = tokio::net::TcpListener::bind(("127.0.0.1", port)).await {
|
||||
listener = Some((l, port));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let (listener, bound_port) = listener.ok_or_else(|| "Failed to bind extension server to any port".to_string())?;
|
||||
println!("Browser extension server bound to 127.0.0.1:{}", bound_port);
|
||||
let listener = tokio::net::TcpListener::bind(("127.0.0.1", EXTENSION_SERVER_PORT))
|
||||
.await
|
||||
.map_err(|e| format!("Failed to bind extension server to port {}: {}", EXTENSION_SERVER_PORT, e))?;
|
||||
|
||||
println!("Browser extension server bound to 127.0.0.1:{}", EXTENSION_SERVER_PORT);
|
||||
|
||||
axum::serve(listener, app)
|
||||
.await
|
||||
|
||||
@@ -837,9 +837,13 @@ pub(crate) async fn start_media_download_internal(
|
||||
let stdout = child.stdout.take().ok_or("Failed to capture stdout")?;
|
||||
|
||||
// yt-dlp parsing regex
|
||||
let pct_re = Regex::new(r"\[download\]\s+(\d+(?:\.\d+)?)%").unwrap();
|
||||
let spd_re = Regex::new(r"at\s+([^\s]+)").unwrap();
|
||||
let eta_re = Regex::new(r"ETA\s+([^\s]+)").unwrap();
|
||||
static PCT_RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
static SPD_RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
static ETA_RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
|
||||
|
||||
let pct_re = PCT_RE.get_or_init(|| Regex::new(r"\[download\]\s+(\d+(?:\.\d+)?)%").unwrap());
|
||||
let spd_re = SPD_RE.get_or_init(|| Regex::new(r"at\s+([^\s]+)").unwrap());
|
||||
let eta_re = ETA_RE.get_or_init(|| Regex::new(r"ETA\s+([^\s]+)").unwrap());
|
||||
|
||||
let _keep_alive = config_path;
|
||||
let mut reader = BufReader::new(stdout).lines();
|
||||
@@ -1195,7 +1199,8 @@ fn toggle_tray_icon(app_handle: tauri::AppHandle, show: bool) -> Result<(), Stri
|
||||
let show_i = MenuItem::with_id(&app_handle, "show", "Show Firelink", true, None::<&str>).map_err(|e| e.to_string())?;
|
||||
let menu = Menu::with_items(&app_handle, &[&show_i, &quit_i]).map_err(|e| e.to_string())?;
|
||||
|
||||
let tray_icon = tauri::image::Image::from_bytes(include_bytes!("../icons/trayTemplate.png")).unwrap();
|
||||
let tray_icon = tauri::image::Image::from_bytes(include_bytes!("../icons/trayTemplate.png"))
|
||||
.map_err(|e| e.to_string())?;
|
||||
let _tray = TrayIconBuilder::with_id("main")
|
||||
.icon(tray_icon)
|
||||
.icon_as_template(true)
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
|
||||
pub fn spawn_scheduler(app_handle: tauri::AppHandle) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
||||
loop {
|
||||
interval.tick().await;
|
||||
|
||||
|
||||
+1
-113
@@ -1,113 +1 @@
|
||||
.logo.vite:hover {
|
||||
filter: drop-shadow(0 0 2em #747bff);
|
||||
}
|
||||
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafb);
|
||||
}
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: 0.75s;
|
||||
}
|
||||
|
||||
.logo.tauri:hover {
|
||||
filter: drop-shadow(0 0 2em #24c8db);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
color: #0f0f0f;
|
||||
background-color: #ffffff;
|
||||
transition: border-color 0.25s;
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #396cd8;
|
||||
}
|
||||
button:active {
|
||||
border-color: #396cd8;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #24c8db;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
color: #ffffff;
|
||||
background-color: #0f0f0f98;
|
||||
}
|
||||
button:active {
|
||||
background-color: #0f0f0f69;
|
||||
}
|
||||
}
|
||||
/* Boilerplate styles cleared */
|
||||
|
||||
@@ -531,7 +531,7 @@ export const AddDownloadsModal = () => {
|
||||
let newName = finalFile;
|
||||
let exists = true;
|
||||
|
||||
while (exists) {
|
||||
while (exists && count < 1000) {
|
||||
newName = `${base} (${count})${ext}`;
|
||||
const storeHas = useDownloadStore.getState().downloads.some(d => {
|
||||
const dest = d.destination || useSettingsStore.getState().defaultDownloadPath || '~/Downloads';
|
||||
|
||||
@@ -57,7 +57,8 @@ export const DownloadTable: React.FC<DownloadTableProps> = ({ filter }) => {
|
||||
} else if (dir === '~') {
|
||||
resolvedDir = await homeDir();
|
||||
}
|
||||
return resolvedDir + '/' + file;
|
||||
const separator = resolvedDir.endsWith('/') ? '' : '/';
|
||||
return resolvedDir + separator + file;
|
||||
};
|
||||
|
||||
const filteredDownloads = downloads.filter((d: DownloadItem) => {
|
||||
|
||||
@@ -247,7 +247,10 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
|
||||
{contextMenu && (
|
||||
<div
|
||||
className="fixed z-50 w-48 py-1 rounded-xl shadow-lg border border-border-modal bg-bg-context-menu backdrop-blur-xl animate-fade-in text-[13px] text-text-primary overflow-hidden"
|
||||
style={{ top: contextMenu.y, left: contextMenu.x }}
|
||||
style={{
|
||||
top: Math.min(contextMenu.y, window.innerHeight - 200),
|
||||
left: Math.min(contextMenu.x, window.innerWidth - 200)
|
||||
}}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user