Permissions
Understanding Kunkun's permission system
Kunkun uses a capability-based permission system to control what extensions can access. Extensions declare required permissions in their manifest, and users approve them at install time. Sensitive operations may require additional runtime prompts.
Permission Types
Simple Permissions
Boolean permissions that grant a specific capability:
{
"permissions": [
"clipboard-read",
"clipboard-write",
"notifications",
"storage",
"path",
"shell",
"dialog",
"open-url",
"open-file",
"open-folder",
"window-control"
]
}| Permission | Description |
|---|---|
clipboard-read | Read clipboard content |
clipboard-write | Write to clipboard |
notifications | Show system notifications |
storage | Use LocalStorage API |
path | Access path utilities |
shell | Execute shell commands |
dialog | Show native dialogs |
open-url | Open URLs in browser |
open-file | Open files with default app |
open-folder | Open folders in file manager |
window-control | Control window properties |
Scoped Permissions
Permissions with specific scope/limitations:
Filesystem
{
"permission": "fs-read",
"allow": ["$HOME/Documents/**", "$DESKTOP/*.png"]
}{
"permission": "fs-write",
"allow": ["$EXTENSION_SUPPORT/**"]
}Network
{
"permission": "network",
"domains": ["*.github.com", "api.example.com"]
}Shell
{
"permission": "shell:execute",
"allow": [
{
"command": "git",
"args": ["clone", "pull", "push"]
}
]
}Path Aliases
Use path aliases for cross-platform compatibility:
| Alias | Description |
|---|---|
$HOME | User home directory |
$DESKTOP | Desktop folder |
$DOCUMENT | Documents folder |
$DOWNLOAD | Downloads folder |
$APPDATA | Application data folder |
$EXTENSION | Extension root directory |
$EXTENSION_SUPPORT | Extension data storage |
Glob Patterns
**- Recursive (all subdirectories)*- Single level*.ext- File extension match
{
"permission": "fs-read",
"allow": [
"$HOME/Documents/**", // All files in Documents and subdirs
"$DESKTOP/*.png", // PNG files on desktop only
"$EXTENSION_SUPPORT/data" // Specific file/folder
]
}Runtime Permission Prompts
Some operations trigger runtime prompts even if declared in the manifest:
import { permissions } from "@kunkunsh/api";
// Request a permission at runtime
const granted = await permissions.request({
permission: "fs-read",
allow: ["$HOME/Downloads/**"]
});
if (granted) {
// Permission was granted
const files = await fs.readDir(downloadsPath);
}Check Permission Status
// Check if a permission is currently granted
const hasAccess = await permissions.check({
permission: "network",
domains: ["api.github.com"]
});
if (!hasAccess) {
// Request the permission
await permissions.request({ /* ... */ });
}List Current Grants
const grants = await permissions.listGrants();
// Returns all currently granted permissions for this extensionGrant Persistence
Permissions are persisted in the database:
- Session grants: Valid until app restart
- Permanent grants: Stored in
permission_grantstable
Grants include metadata:
grantedAt: Timestamp when grantedpermissionType: Type of permissionscopePattern: The specific scope granted
Permission Enforcement
Plugin API Layer
All API calls go through permission checks:
// In the main process
async function readFile(path: string) {
await requirePermission({ permission: "fs-read", path });
// ... actual file read
}Service Permission Intersection
When Plugin A calls Plugin B's service:
Effective Permissions = Caller Permissions ∩ Service Permissions- Simple permissions: Set intersection
- Scoped permissions: Intersect allow lists, union deny lists
This prevents privilege escalation through service calls.
Development Mode
In development mode, you can bypass permission prompts:
{
"kunkun": {
"devMode": {
"bypassPermissions": true
}
}
}This is useful for testing but should never be used in production extensions.
Permission Schema
Full permission type definition:
type Permission =
| string // Simple permission like "clipboard-read"
| {
permission: "fs-read" | "fs-write";
allow?: string[];
deny?: string[];
}
| {
permission: "network";
domains: string[];
}
| {
permission: "shell:execute" | "shell:spawn";
allow: Array<{
command: string;
args?: string[];
}>;
};Best Practices
- Request minimum permissions: Only ask for what you need
- Use scoped permissions: Limit filesystem/network access to specific paths/domains
- Handle denials gracefully: Check permissions before operations
- Document requirements: Explain why each permission is needed
- Request at runtime for sensitive ops: Ask just before performing the action
Example: Full Permission Declaration
{
"kunkun": {
"identifier": "com.example.my-extension",
"permissions": [
"clipboard-read",
"clipboard-write",
"notifications",
"storage",
"path",
{
"permission": "fs-read",
"allow": [
"$HOME/Documents/**",
"$DESKTOP/**"
]
},
{
"permission": "fs-write",
"allow": [
"$EXTENSION_SUPPORT/**"
]
},
{
"permission": "network",
"domains": [
"*.github.com",
"api.example.com"
]
}
]
}
}This grants:
- Clipboard read/write access
- Notification permission
- Local storage access
- Path utilities
- Read access to Documents and Desktop
- Write access to extension support directory only
- Network access to GitHub and example.com APIs