r2papi
Version:
r2api on top of r2pipe for typescript and js
217 lines (203 loc) • 5.93 kB
text/typescript
// shell utilities on top of r2pipe
import { R2Papi } from "./r2papi.js";
/**
* Interface to hold the name and description for every filesystem type parser implementation.
*
* @typedef FileSystemType
*/
export interface FileSystemType {
/**
* name of the filesystem format, to be used when mounting it.
*
* @type {string}
*/
name: string;
/**
* short string that describes the plugin
*
* @type {string}
*/
description: string;
}
/**
* Global static class providing information about the actual radare2 in use.
* This class mimics the `Frida` global object in frida, which can be useful to
* determine the executing environment of the script
*
* @typedef Radare2
*/
export interface Radare2 {
/**
* string representing the radare2 version (3 numbers separated by dots)
*
* @type {string}
*/
version: string;
}
/**
* Class that interacts with the `r2ai` plugin (requires `rlang-python` and `r2i` r2pm packages to be installed).
* Provides a way to script the interactions with different language models using javascript from inside radare2.
*
* @typedef R2Shell
*/
export class R2Shell {
/**
* Keep a reference to the associated r2papi instance
*
* @type {R2Papi}
*/
public rp: R2Papi;
/**
* Create a new instance of the R2Shell
*
* @param {R2Papi} take the R2Papi intance to used as backend to run the commands
* @returns {R2Shell} instance of the shell api
*/
constructor(papi: R2Papi) {
this.rp = papi;
}
/**
* Create a new directory in the host system, if the opational recursive argument is set to
* true it will create all the necessary subdirectories instead of just the specified one.
*
* @param {string} text path to the new directory to be created
* @param {boolean?} disabled by default, but if it's true, it will create subdirectories recursively if necessary
* @returns {boolean} true if successful
*/
mkdir(file: string, recursive?: boolean): boolean {
if (recursive === true) {
this.rp.call(`mkdir -p ${file}`);
} else {
this.rp.call(`mkdir ${file}`);
}
return true;
}
/**
* Deletes a file
*
* @param {string} path to the file to remove
* @returns {boolean} true if successful
*/
unlink(file: string): boolean {
this.rp.call(`rm ${file}`);
return true;
}
/**
* Change current directory
*
* @param {string} path to the directory
* @returns {boolean} true if successful
*/
chdir(path: string): boolean {
this.rp.call(`cd ${path}`);
return true;
}
/**
* List files in the current directory
*
* @returns {string[]} array of file names
*/
ls(): string[] {
const files = this.rp.call(`ls -q`);
return files.trim().split("\n");
}
/**
* TODO: Checks if a file exists (not implemented)
*
* @returns {boolean} true if the file exists, false if it does not
*/
fileExists(path: string): boolean {
// TODO
return false;
}
/**
* Opens an URL or application
* Execute `xdg-open` on linux, `start` on windows, `open` on Mac
*
* @param {string} URI or file to open by the system
*/
open(arg: string): void {
this.rp.call(`open ${arg}`);
}
/**
* Run a system command and get the return code
*
* @param {string} system command to be executed
* @returns {number} return code (0 is success)
*/
system(cmd: string): number {
this.rp.call(`!${cmd}`);
return 0;
}
/**
* Mount the given offset on the specified path using the filesytem.
* This is not a system-level mountpoint, it's using the internal filesystem abstraction of radare2.
*
* @param {string} filesystem type name (see .
* @param {string} system command to be executed
* @param {string|number}
* @returns {number} return code (0 is success)
*/
mount(fstype: string, path: string, offset: string | number): boolean {
if (!offset) {
offset = 0;
}
this.rp.call(`m ${fstype} ${path} ${offset}`);
return true;
}
/**
* Unmount the mountpoint associated with the given path.
*
* @param {string} path to the mounted filesystem
* @returns {void} TODO: should return boolean
*/
umount(path: string): void {
this.rp.call(`m-${path}`);
}
/**
* Change current directory on the internal radare2 filesystem
*
* @param {string} path name to change to
* @returns {void} TODO: should return boolean
*/
chdir2(path: string): void {
this.rp.call(`mdq ${path}`);
}
/**
* List the files contained in the given path within the virtual radare2 filesystem.
*
* @param {string} path name to change to
* @returns {void} TODO: should return boolean
*/
ls2(path: string): string[] {
const files = this.rp.call(`mdq ${path}`);
return files.trim().split("\n");
}
/**
* Enumerate all the mountpoints set in the internal virtual filesystem of radare2
* @returns {any[]} array of mount
*/
enumerateFilesystemTypes(): any[] {
return this.rp.cmdj("mLj");
}
/**
* Enumerate all the mountpoints set in the internal virtual filesystem of radare2
* @returns {any[]} array of mount
*/
enumerateMountpoints(): any[] {
const output = this.rp.cmdj("mj");
return output["mountpoints"];
}
/**
* TODO: not implemented
*/
isSymlink(file: string): boolean {
return false;
}
/**
* TODO: not implemented
*/
isDirectory(file: string): boolean {
return false;
}
}