-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add SQL and UI Styling guides and concepts
* Lunch break. * Ready for review. * Optimised images with calibre/image-actions * Link fix. * Re-review. * Optimised images with calibre/image-actions * Now ready. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
cf57780
commit 8ac07db
Showing
17 changed files
with
362 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# UI Styling | ||
|
||
When using the Caido [community plugin template](https://github.com/caido-community/create-plugin), you have the option to customize the user-interface. | ||
|
||
For this, Caido uses the following dependencies: | ||
|
||
- [Vue.js](https://vuejs.org/): A JavaScript framework for building user-interfaces. | ||
- [PrimeVue](https://primevue.org/): A library for Vue.js that provides a wide range of pre-built UI components. | ||
- [TailWind CSS](https://tailwindcss.com/): A CSS framework that allows applications to be styled using predefined utility classes. | ||
|
||
The `@caido/primevue` and `@caido/tailwindcss` packages are custom adaptations that are configured to align with the theme of the Caido application. | ||
|
||
The `tailwindcss-primeui` package acts as a bridge, allowing PrimeVue components to be styled using Tailwind CSS. | ||
|
||
Within the `tailwind.config.ts` file, both the `tailwindPrimeui` and `tailwindCaido` plugins are imported to inject the necessary classes. | ||
|
||
By leveraging these technologies and creating relationships between them, we are able to customize and maintain consistency in the appearance of the frontend component of Caido plugins. | ||
|
||
## What's next? | ||
|
||
[Learn how to use the PrimeVue library to build a plugin frontend.](/guides/components/styling.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Handling Backend Events | ||
|
||
In this guide, you will learn how to handle backend events in the frontend of your Caido plugin. | ||
|
||
This can be accomplished using the three event handlers provided by the SDK: | ||
|
||
## onProjectChange | ||
|
||
An event will be triggered when the active [Project](https://docs.caido.io/quickstart/beginner_guide/first_steps_with_caido/project.html) changes. | ||
|
||
### /packages/backend/src/index.ts | ||
|
||
``` ts | ||
import type { DefineAPI, SDK } from "caido:plugin"; | ||
|
||
export type API = DefineAPI<{}>; | ||
|
||
let previousProject: string | null = null; | ||
|
||
export function init(sdk: SDK<API>) { | ||
sdk.events.onProjectChange((sdk, project) => { | ||
const newProjectName = project?.getName() ?? null; | ||
sdk.console.log(`Project changed from "${previousProject}" to "${newProjectName}."`); | ||
previousProject = newProjectName; | ||
}); | ||
} | ||
``` | ||
|
||
## The Result | ||
|
||
``` txt | ||
Project changed from "Caido" to "Example". | ||
``` | ||
|
||
## onInterceptRequest and onInterceptResponse | ||
|
||
An event will be triggered with `onInterceptRequest` and `onInterceptResponse` when a request or response is proxied through Caido respectively. | ||
|
||
### /packages/backend/src/index.ts | ||
|
||
``` ts | ||
import type { DefineAPI, SDK } from "caido:plugin"; | ||
import type { Request, Response } from "caido:utils"; | ||
|
||
export type API = DefineAPI<{}>; | ||
|
||
export function init(sdk: SDK<API>) { | ||
sdk.events.onInterceptRequest((sdk, request: Request) => { | ||
sdk.console.log(`Intercepted ${request.getMethod()} request to ${request.getUrl()}`); | ||
}); | ||
|
||
sdk.events.onInterceptResponse((sdk, request: Request, response: Response) => { | ||
sdk.console.log(`Intercepted response from ${request.getUrl()} with status ${response.getCode()}`); | ||
}); | ||
} | ||
``` | ||
|
||
## The Result | ||
|
||
``` txt | ||
Intercepted GET request to https://example.com/path | ||
Intercepted response from https://example.com/path with status 304 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
# Storing Data in SQLite | ||
|
||
For storing data generated by your plugin, Caido utilizes SQLite databases. | ||
|
||
SQLite is a lightweight database engine made available via a small library. It requires no setup, administration or separate server. Instead, all data is stored in a single file. | ||
|
||
## Getting a Database Path | ||
|
||
The `sdk.meta.db()` utility provides a SQLite database specific to your plugin. You can view the location of the generated file using `sdk.meta.path()`: | ||
|
||
``` ts | ||
const db = await sdk.meta.db(); | ||
|
||
const dataPath = sdk.meta.path(); | ||
sdk.console.log(`Database will be stored in: ${dataPath}`); | ||
``` | ||
|
||
## Creating Tables | ||
|
||
You can run direct SQL statements by supplying them as an arguement to the `.exec()` method: | ||
|
||
``` ts | ||
// Create a new table if it doesn't exist. | ||
// This will create a table named "test" with two columns: id and name. | ||
await db.exec(` | ||
CREATE TABLE IF NOT EXISTS test ( | ||
id INTEGER PRIMARY KEY, | ||
name TEXT NOT NULL | ||
); | ||
`); | ||
``` | ||
|
||
## Inserting Rows | ||
|
||
Instead of using direct statements every time you want to add to a table, you can use `.prepare()` to create predefined statements with placeholders, marked with `(?)` for new entry values. | ||
|
||
Then, you can execute these prepared statements with the `.run()` method that takes the placeholder values as arguements: | ||
|
||
``` ts | ||
const insertStatement = await db.prepare("INSERT INTO test (name) VALUES (?)"); | ||
|
||
// Execute the insert statement to add "Ninjeeter" as a name entry. | ||
const result = await insertStatement.run("Ninjeeter"); | ||
``` | ||
|
||
## Retrieving Data | ||
|
||
Using `.lastInsertRowid` will return the ID of the last inserted row: | ||
|
||
``` ts | ||
console.log(`Inserted row with ID: ${result.lastInsertRowid}`); | ||
``` | ||
|
||
To select all the columns in a table and return every row, use the wildcard character `*` and the `.all()` method: | ||
|
||
``` ts | ||
const selectStatement = await db.prepare("SELECT * FROM test"); | ||
const rows = await selectStatement.all(); | ||
sdk.console.log("Current records: " + JSON.stringify(rows)); | ||
``` | ||
|
||
You can return specific rows by preparing a statement and using the `.get()` method which takes an arguement that will be used to match the table entry: | ||
|
||
``` ts | ||
// Prepare a statement to get a single row by ID | ||
const getByIdStatement = await db.prepare("SELECT * FROM test WHERE id = ?"); | ||
|
||
// Returns the first matching row or undefined if none found. | ||
const row = await getByIdStatement.get(1); // Get row with ID 1. | ||
|
||
if (row) { | ||
sdk.console.log(`Found record: ${JSON.stringify(row)}`); | ||
} else { | ||
sdk.console.log("No record found with that ID"); | ||
} | ||
``` | ||
|
||
### /packages/backend/src/index.ts | ||
|
||
``` ts | ||
import type { DefineAPI, SDK } from "caido:plugin"; | ||
|
||
async function initDatabase(sdk: SDK) { | ||
try { | ||
const db = await sdk.meta.db(); | ||
|
||
const dataPath = sdk.meta.path(); | ||
sdk.console.log(`Database will be stored in: ${dataPath}`); | ||
|
||
await db.exec(` | ||
CREATE TABLE IF NOT EXISTS test ( | ||
id INTEGER PRIMARY KEY, | ||
name TEXT NOT NULL | ||
); | ||
`); | ||
|
||
const insertStatement = await db.prepare("INSERT INTO test (name) VALUES (?)"); | ||
const result = await insertStatement.run("foo"); | ||
sdk.console.log(`Inserted row with ID: ${result.lastInsertRowid}`); | ||
|
||
const selectStatement = await db.prepare("SELECT * FROM test"); | ||
const rows = await selectStatement.all(); | ||
sdk.console.log("Current records: " + JSON.stringify(rows)); | ||
|
||
const getByIdStatement = await db.prepare("SELECT * FROM test WHERE id = ?"); | ||
|
||
const row = await getByIdStatement.get(1); | ||
|
||
if (row) { | ||
sdk.console.log(`Found record: ${JSON.stringify(row)}`); | ||
} else { | ||
sdk.console.log("No record found with that ID"); | ||
} | ||
|
||
return db; | ||
} catch (error) { | ||
sdk.console.error(`Database initialization failed: ${error}`); | ||
throw error; | ||
} | ||
} | ||
|
||
export type API = DefineAPI<{ | ||
}>; | ||
|
||
export async function init(sdk: SDK<API>) { | ||
await initDatabase(sdk); | ||
sdk.console.log("Database initialized."); | ||
} | ||
``` | ||
|
||
## The Result | ||
|
||
In your backend logs, you will see the following entries: | ||
|
||
``` txt | ||
Database will be stored in: [~]\Caido\data\plugins\[PLUGIN UUID] | ||
Inserted row with ID: 1 | ||
Current records: [{"id":1,"name":"Ninjeeter"}] | ||
Found record: {"id":1,"name":"Ninjeeter"} | ||
``` |
Oops, something went wrong.