fix: harden security, eliminate panics, remove dead code, add Dockerfile
Security: - Use constant-time password comparison (subtle crate) to prevent timing attacks - Replace permissive CORS with configurable origin-restricted CORS - Add TLS warning when password auth is used without HTTPS Bug fixes: - Convert MetaPlugin panics to anyhow::Result (get_meta_plugin, outputs_mut, options_mut) - Replace item.id.unwrap() with proper error handling across 15 call sites - Fix panic on unknown column type in list mode - Fix conflicting PIPESIZE constant (was 8192 vs 65536, now unified to 8192) - Add 256MB filter chain buffer limit to prevent OOM - Gracefully skip unregistered plugins instead of panicking Dead code removal: - Delete unused filter parser files (filter_parser.rs, filter.pest, parser/ module) - ~260 lines of dead PEG parser code removed Code consolidation: - Add is_content_binary_from_metadata() helper (was duplicated in 4 places) - Simplify save_item_raw() to delegate to save_item_raw_streaming() (~90 lines removed) Incomplete features: - Populate filter_plugins in status output from global registry - Add FallbackMagicFileMetaPlugin (was referenced but never implemented) - Document init_plugins() as intentional no-op Infrastructure: - Add Dockerfile (static musl binary on scratch, 4.8MB) - Add .dockerignore - Add cors_origin to ServerConfig and config.rs
This commit is contained in:
@@ -234,18 +234,14 @@ impl ItemService {
|
||||
compression: &str,
|
||||
metadata: &HashMap<String, String>,
|
||||
) -> Result<bool, CoreError> {
|
||||
// Check if we already have text metadata
|
||||
if let Some(text_val) = metadata.get("text") {
|
||||
return Ok(text_val == "false");
|
||||
}
|
||||
|
||||
// Read only the first 8192 bytes for binary detection
|
||||
let mut sample_reader = self
|
||||
.compression_service
|
||||
.stream_item_content(item_path, compression)?;
|
||||
let mut sample_buffer = vec![0; 8192];
|
||||
let bytes_read = sample_reader.read(&mut sample_buffer)?;
|
||||
Ok(crate::common::is_binary::is_binary(
|
||||
Ok(crate::common::is_binary::is_content_binary_from_metadata(
|
||||
metadata,
|
||||
&sample_buffer[..bytes_read],
|
||||
))
|
||||
}
|
||||
@@ -516,7 +512,9 @@ impl ItemService {
|
||||
|
||||
let mut result = Vec::new();
|
||||
for item in items {
|
||||
let item_id = item.id.unwrap();
|
||||
let item_id = item
|
||||
.id
|
||||
.ok_or_else(|| CoreError::InvalidInput("Item missing ID".to_string()))?;
|
||||
let tags = tags_map.get(&item_id).cloned().unwrap_or_default();
|
||||
let meta_hm = meta_map_db.get(&item_id).cloned().unwrap_or_default();
|
||||
let meta = meta_hm
|
||||
@@ -636,7 +634,9 @@ impl ItemService {
|
||||
let mut item;
|
||||
{
|
||||
item = db::create_item(conn, compression_type.clone())?;
|
||||
item_id = item.id.unwrap();
|
||||
item_id = item
|
||||
.id
|
||||
.ok_or_else(|| CoreError::InvalidInput("Item missing ID".to_string()))?;
|
||||
debug!("ITEM_SERVICE: Created new item with id: {item_id}");
|
||||
db::set_item_tags(conn, item.clone(), tags)?;
|
||||
debug!("ITEM_SERVICE: Set tags for item {item_id}");
|
||||
@@ -770,7 +770,9 @@ impl ItemService {
|
||||
|
||||
{
|
||||
item = db::create_item(conn, compression_type.clone())?;
|
||||
item_id = item.id.unwrap();
|
||||
item_id = item
|
||||
.id
|
||||
.ok_or_else(|| CoreError::InvalidInput("Item missing ID".to_string()))?;
|
||||
debug!("ITEM_SERVICE: Created MCP item with id: {item_id}");
|
||||
|
||||
// Add tags
|
||||
|
||||
Reference in New Issue
Block a user