дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
Closes #1947 Adds API 1.3 `fs.plugin-dir`: a persistent owner-only directory per plugin (0700 directories / 0600 files on Unix, owner-only ACL on Windows), separate from the packaged code, storage and secrets. The plugin reads and writes under it without fs.* grants, can open files there in the editor and pass their paths to approved programs; editor saves keep the protection, restart keeps the content, uninstall removes it. Traversal and symlink escapes into other plugins' directories are rejected (real-Wasm regressions). Co-authored-by: arnaud-ritti <[email protected]>
64 рядки
2.7 KiB
Rust
64 рядки
2.7 KiB
Rust
use openidea_plugin::{Context, Error, Invocation, Plugin, host, register_plugin};
|
|
|
|
#[derive(Default)]
|
|
struct PrivateDir;
|
|
|
|
impl Plugin for PrivateDir {
|
|
fn activate(&mut self, _: &Context) -> Result<(), Error> {
|
|
// Activation has no project or focused window.
|
|
host::fs::plugin_dir().map(drop)
|
|
}
|
|
|
|
fn run_command(&mut self, id: &str, _: &Invocation, arg: Option<&str>) -> Result<Option<String>, Error> {
|
|
let dir = host::fs::plugin_dir()?;
|
|
let path = format!("{dir}/fake-secret.txt");
|
|
match id {
|
|
"directory" => Ok(Some(dir)),
|
|
"roundtrip" => {
|
|
host::fs::write_file(&path, "fake private data\n")?;
|
|
let bytes = host::fs::read_bytes(&path)?;
|
|
host::fs::write_bytes(&format!("{dir}/cache.bin"), &bytes)?;
|
|
if host::fs::stat(&path)?.size != bytes.len() as u64 || host::fs::read_dir(&dir)?.len() < 2 {
|
|
return Err("private filesystem roundtrip failed".into());
|
|
}
|
|
host::fs::read_file(&path).map(Some)
|
|
}
|
|
"large-cache" => {
|
|
let bytes = vec![b'x'; 8 << 20];
|
|
let mut total = 0;
|
|
for index in 0..10 {
|
|
let file = format!("{dir}/cache-{index}.bin");
|
|
host::fs::write_bytes(&file, &bytes)?;
|
|
total += host::fs::stat(&file)?.size;
|
|
}
|
|
Ok(Some(total.to_string()))
|
|
}
|
|
"read" => host::fs::read_file(arg.unwrap_or(&path)).map(Some),
|
|
"write" => host::fs::write_file(arg.unwrap_or(&path), "fake replacement\n").map(|()| None),
|
|
"open" => host::open_location(&path, 0, 0).map(|()| Some(path)),
|
|
"process" => host::run_process("cat", &[path], None).map(|out| Some(out.stdout)),
|
|
_ => Err(Error::NotFound(id.into())),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl openidea_plugin::providers::Providers for PrivateDir {
|
|
fn completion(
|
|
&mut self,
|
|
_: &openidea_plugin::providers::Document,
|
|
_: openidea_plugin::Position,
|
|
_: Option<&str>,
|
|
) -> Vec<openidea_plugin::providers::CompletionItem> {
|
|
let Ok(dir) = host::fs::plugin_dir() else { return Vec::new() };
|
|
let path = format!("{dir}/fake-secret.txt");
|
|
let Ok(text) = host::fs::read_file(&path) else { return Vec::new() };
|
|
// Providers may read their content but must not open an editor.
|
|
if host::open_location(&path, 0, 0).is_ok() {
|
|
return Vec::new();
|
|
}
|
|
vec![openidea_plugin::providers::CompletionItem::new(&text, openidea_plugin::providers::CompletionKind::Text)]
|
|
}
|
|
}
|
|
|
|
register_plugin!(PrivateDir, providers);
|