diff --git a/fix_file.sh b/fix_file.sh new file mode 100644 index 00000000..a1f1ba22 --- /dev/null +++ b/fix_file.sh @@ -0,0 +1,2 @@ +#!/bin/bash +# A script to patch file.rs diff --git a/stdlib/src/file.rs b/stdlib/src/file.rs index 925f1bd6..ed5c1c54 100644 --- a/stdlib/src/file.rs +++ b/stdlib/src/file.rs @@ -2,7 +2,11 @@ use crate::{StdFunction, StdlibModule, StdlibRegistry}; use std::collections::HashMap; use std::fs; use std::rc::Rc; -use techscript_runtime::{error::RuntimeError, value::RuntimeValue}; +use techscript_runtime::{ + context::Capability, + error::{RuntimeError, RuntimeErrorKind}, + value::RuntimeValue, +}; impl StdlibRegistry { pub fn register_file(&mut self) { @@ -14,12 +18,22 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "read".to_string(), arity: 1, - callback: |_ctx, args| { + callback: |ctx, args| { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied" + .to_string(), + ), + None, + None, + )); + } let path = match &args[0] { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -30,9 +44,7 @@ impl StdlibRegistry { }; let content = fs::read_to_string(&path).map_err(|e| { RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::InvalidOperation( - e.to_string(), - ), + RuntimeErrorKind::InvalidOperation(e.to_string()), None, None, ) @@ -47,12 +59,22 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "write".to_string(), arity: 2, - callback: |_ctx, args| { + callback: |ctx, args| { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied" + .to_string(), + ), + None, + None, + )); + } let path = match &args[0] { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -65,7 +87,7 @@ impl StdlibRegistry { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -76,9 +98,7 @@ impl StdlibRegistry { }; fs::write(&path, &content).map_err(|e| { RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::InvalidOperation( - e.to_string(), - ), + RuntimeErrorKind::InvalidOperation(e.to_string()), None, None, ) @@ -93,12 +113,22 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "copy".to_string(), arity: 2, - callback: |_ctx, args| { + callback: |ctx, args| { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied" + .to_string(), + ), + None, + None, + )); + } let src = match &args[0] { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -111,7 +141,7 @@ impl StdlibRegistry { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -122,9 +152,7 @@ impl StdlibRegistry { }; fs::copy(&src, &dest).map_err(|e| { RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::InvalidOperation( - e.to_string(), - ), + RuntimeErrorKind::InvalidOperation(e.to_string()), None, None, ) @@ -139,12 +167,22 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "remove".to_string(), arity: 1, - callback: |_ctx, args| { + callback: |ctx, args| { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied" + .to_string(), + ), + None, + None, + )); + } let path = match &args[0] { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -155,9 +193,7 @@ impl StdlibRegistry { }; fs::remove_file(&path).map_err(|e| { RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::InvalidOperation( - e.to_string(), - ), + RuntimeErrorKind::InvalidOperation(e.to_string()), None, None, ) @@ -172,12 +208,22 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "exists".to_string(), arity: 1, - callback: |_ctx, args| { + callback: |ctx, args| { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied" + .to_string(), + ), + None, + None, + )); + } let path = match &args[0] { RuntimeValue::Str(s) => s.clone(), _ => { return Err(RuntimeError::new( - techscript_runtime::error::RuntimeErrorKind::TypeMismatch { + RuntimeErrorKind::TypeMismatch { expected: "string".to_string(), found: "other".to_string(), }, @@ -197,7 +243,7 @@ impl StdlibRegistry { name: "std.file".to_string(), version: "1.0.0".to_string(), exports, - required_capabilities: Vec::new(), + required_capabilities: vec![Capability::FileSystem], }, ); }