Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-vnidrop-fs"
version = "1.0.0-rc.1"
version = "1.0.0-rc"
authors = [ "AbassHammed" ]
description = "Cross-platform filesystem manager for Tauri with Android SAF and iOS document picker support."
edition = "2021"
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,15 @@ configuration is:
}
```

For production, prefer a tighter scope:
The plugin default is intentionally read-only. It enables metadata, read,
picker, and non-mutating helper commands, but not create, write, rename,
delete, or persisted permission lifecycle commands. For production, prefer a
tighter scope and opt into only the command profile your app needs:

```json
{
"permissions": [
"vnidrop-fs:all-without-delete",
"vnidrop-fs:read-only",
{
"identifier": "vnidrop-fs:scope",
"allow": ["$APPDATA/files/**/*"],
Expand All @@ -102,8 +105,9 @@ Treat filesystem access as an explicit capability:

- Prefer picker-returned mobile URI objects over raw paths.
- Keep production capability files narrow. Do not ship `vnidrop-fs:all`,
`fs:read-all`, `fs:write-all`, or `"allow": ["**"]` unless the whole app is
intended to manage every reachable file.
`vnidrop-fs:all-without-delete`, `fs:read-all`, `fs:write-all`, or
`"allow": ["**"]` unless the whole app is intended to manage every reachable
file.
- Android `content://` operations are authorized by Android URI permissions and
document providers. Destructive operations such as rename and delete should
only be exposed in your UI for URIs the user selected or the app created.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vnidrop/tauri-plugin-fs",
"version": "1.0.0-rc.1",
"version": "1.0.0-rc",
"author": "AbassHammed",
"description": "Cross-platform filesystem manager for Tauri with Android SAF and iOS document picker support.",
"keywords": [
Expand Down
15 changes: 14 additions & 1 deletion permissions/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Default permissions for the plugin

#### This default permission set includes the following:

- `all-without-delete`
- `read-only`

## Permission Table

Expand Down Expand Up @@ -1422,6 +1422,19 @@ Denies the write_text_file command without any pre-configured scope.
<tr>
<td>

`vnidrop-fs:read-only`

</td>
<td>

This enables read-only commands and non-mutating picker/metadata helpers.

</td>
</tr>

<tr>
<td>

`vnidrop-fs:scope`

</td>
Expand Down
2 changes: 1 addition & 1 deletion permissions/default.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[default]
description = "Default permissions for the plugin"
permissions = [
"all-without-delete"
"read-only"
]
44 changes: 44 additions & 0 deletions permissions/read-only.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"$schema" = "schemas/schema.json"

[[permission]]
identifier = "read-only"
description = "This enables read-only commands and non-mutating picker/metadata helpers."
commands.allow = [
"get_android_api_level",
"get_name",
"get_byte_length",
"get_type",
"get_mime_type",
"get_metadata",
"get_thumbnail",
"get_thumbnail_as_bytes",
"get_thumbnail_as_base64",
"get_thumbnail_as_data_url",
"get_fs_path",
"list_volumes",
"check_public_files_permission",
"count_all_file_streams",
"close_all_file_streams",
"open_read_file_stream",
"open_read_text_file_lines_stream",
"read_file",
"read_file_as_base64",
"read_file_as_data_url",
"read_text_file",
"read_dir",
"check_picker_uri_permission",
"check_persisted_picker_uri_permission",
"show_open_file_picker",
"show_open_dir_picker",
"show_view_file_dialog",
"show_view_dir_dialog",
"listSecurityScopedBookmarks",
"resolveSecurityScopedBookmark",
"readFile",
"readTextFile",
"readDir",
"exists",
"getMetadata",
"showOpenFilePicker",
"showOpenDirPicker"
]
10 changes: 8 additions & 2 deletions permissions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -943,10 +943,16 @@
"markdownDescription": "Denies the write_text_file command without any pre-configured scope."
},
{
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `all-without-delete`",
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `read-only`",
"type": "string",
"const": "default",
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `all-without-delete`"
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `read-only`"
},
{
"description": "This enables read-only commands and non-mutating picker/metadata helpers.",
"type": "string",
"const": "read-only",
"markdownDescription": "This enables read-only commands and non-mutating picker/metadata helpers."
},
{
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"permissions\": [\n \"vnidrop-fs:all-without-delete\",\n {\n \"identifier\": \"vnidrop-fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
Expand Down
33 changes: 31 additions & 2 deletions tests/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,39 @@ fn all_permission_contains_mutating_and_picker_commands() {
}

#[test]
fn default_permission_uses_non_delete_profile() {
fn default_permission_uses_read_only_profile() {
let contents = fs::read_to_string("permissions/default.toml").expect("default permission file should exist");

assert!(contents.contains(r#""all-without-delete""#));
assert!(contents.contains(r#""read-only""#));
}

#[test]
fn read_only_excludes_mutating_commands() {
let contents = fs::read_to_string("permissions/read-only.toml").expect("read-only permission file should exist");

for command in [
"create_new_file",
"create_new_dir",
"create_new_public_file",
"write_file",
"copy_file",
"rename_file",
"remove_file",
"remove_dir_all",
"persist_picker_uri_permission",
"release_persisted_picker_uri_permission",
"persistSecurityScopedBookmark",
"releaseSecurityScopedBookmark",
"createNewFile",
"writeFile",
"renameFile",
"removeFile",
] {
assert!(
!contents.contains(&format!(r#""{command}""#)),
"read-only should not include {command}"
);
}
}

#[test]
Expand Down
Loading