-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Add Vim Leader Key extension #24407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add Vim Leader Key extension #24407
Conversation
|
Congratulations on your new Raycast extension! 🚀 Due to our current reduced availability, the initial review may take up to 10-15 business days. Once the PR is approved and merged, the extension will be available on our Store. |
Greptile OverviewGreptile SummaryThis PR adds a new "Vim Leader Key" extension that brings Vim-style hierarchical hotkeys to Raycast. The extension allows users to create nested menus of shortcuts with single-key navigation, supporting applications, URLs, folders, and shell commands. It includes JSON import/export functionality, timeout configuration, and a visual editor. Key Features
Issues FoundCritical Security Issuesactions.ts contains shell injection vulnerabilities in Syntax Issues
Code QualityThe extension demonstrates good architecture with:
The forms, import/export functionality, and type definitions are well-implemented with no issues found. Confidence Score: 2/5
Important Files ChangedFile Analysis
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 files reviewed, 4 comments
| interface Preferences { | ||
| enableTimeout: boolean; | ||
| timeoutSeconds: string; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Manual Preferences interface definitions are not needed and can cause type mismatches. Raycast auto-generates preference types in raycast-env.d.ts when the extension runs, which you should import instead.
Remove this manual interface definition and import the auto-generated Preferences type from @raycast/api:
| interface Preferences { | |
| enableTimeout: boolean; | |
| timeoutSeconds: string; | |
| } | |
| // Remove this manual interface - preferences are auto-generated |
After the extension is built, you can import preferences types that are auto-generated based on your package.json preferences configuration.
| } | ||
|
|
||
| export function generateId(): string { | ||
| return Date.now().toString(36) + Math.random().toString(36).substr(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
substr() is deprecated in JavaScript. Use substring() or slice() instead.
| return Date.now().toString(36) + Math.random().toString(36).substr(2); | |
| return Date.now().toString(36) + Math.random().toString(36).substring(2); |
| async function openApp(appPath: string): Promise<void> { | ||
| if (appPath.endsWith(".app")) { | ||
| await execAsync(`open "${appPath}"`); | ||
| } else { | ||
| await execAsync(`open -a "${appPath}"`); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The command execution here is vulnerable to shell injection if the appPath contains special characters like quotes, backticks, or dollar signs. While double quotes provide some protection, they don't escape all dangerous characters.
For example, if appPath is test"$(malicious)", the command would execute arbitrary code.
Consider using Raycast's open() API for opening applications instead of shell commands, or properly escape the path using a library that handles all shell metacharacters:
| async function openApp(appPath: string): Promise<void> { | |
| if (appPath.endsWith(".app")) { | |
| await execAsync(`open "${appPath}"`); | |
| } else { | |
| await execAsync(`open -a "${appPath}"`); | |
| } | |
| } | |
| async function openApp(appPath: string): Promise<void> { | |
| // Use Raycast's open() API which is safer | |
| if (appPath.endsWith(".app")) { | |
| await open(appPath); | |
| } else { | |
| await open(appPath); | |
| } | |
| } |
If you must use shell commands, use proper escaping or pass arguments as an array to avoid shell interpretation.
| async function openFolder(folderPath: string): Promise<void> { | ||
| await execAsync(`open "${folderPath}"`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same shell injection vulnerability as the openApp function. The folderPath is not properly escaped and can contain malicious characters.
| async function openFolder(folderPath: string): Promise<void> { | |
| await execAsync(`open "${folderPath}"`); | |
| } | |
| async function openFolder(folderPath: string): Promise<void> { | |
| await open(folderPath); // Use Raycast's open() API instead | |
| } |
- update metadata images
Description
Adds a new extension "Vim Leader Key" that brings Vim-style hierarchical hotkeys to Raycast.
It allows users to create nested menus of shortcuts (e.g., 'c' for Calculator, 'a' then 'f' for Finder) that can launch apps, run commands, or open URLs.
Features include JSON import/export, timeout configuration, and a visual editor for key bindings.
Screencast:
(Drag and drop your screenshots here. If you recorded a short video/gif, that's even better, but screenshots are fine.)
Checklist: