-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement plugin system and add demo plugin for twitter profile (…
…#59) * wip: testing extism host function * wip * wip * wip: adding ui for plugin * feat: add cache for headers and cookies by host * feat: add plugin stores * feat: add a plugin and render plugin list * feat: add plugin config db * feat: add basic plugin steps ui * feat: add completion status to steps ui * fix: refactor twitter profile plugin * fix: refactor steps execution * fix: testing plugin * Added README to plugins folder * feat: fix twitter profile plugin * improved README: document how to run the twitter plugin example * remove ddos * WIP: Reddit plugin * fix: steps circular reference * feat: open popup * Reddit plugin (result too big) * feat: add view proof * chore: add plugins to eslint ignore * fix: twitter plugin * fix: remove logs * feat: add permission for approved request, notary, and proxy url in plugin --------- Co-authored-by: Hendrik Eeckhaut <[email protected]>
- Loading branch information
Showing
41 changed files
with
1,666 additions
and
236 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
"wasm", | ||
"tlsn", | ||
"util", | ||
"plugins", | ||
"webpack.config.js" | ||
] | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,48 @@ | ||
# Plugin Development for the TLSNotary Browser Extension | ||
|
||
This folder is dedicated to the development of plugins for the TLSNotary browser extension, utilizing the Extism framework. Currently, the folder includes a TypeScript-based plugin example, `twitter_profile`, with plans to add more plugins showcasing different programming languages and functionalities. | ||
|
||
## Installation of Extism-js | ||
|
||
1. **Download and Install Extism-js**: Begin by setting up `extism-js`, which enables you to compile and manage your plugins. Run these commands to download and install it: | ||
|
||
```sh | ||
curl -O https://raw.githubusercontent.com/extism/js-pdk/main/install.sh | ||
sh install.sh | ||
``` | ||
|
||
This script installs the Extism JavaScript Plugin Development Kit from its GitHub repository, preparing your environment for plugin compilation. | ||
|
||
## Building the Twitter Profile Plugin | ||
|
||
Navigate to the `twitter_profile` directory within this folder and run the following command to build the plugin: | ||
|
||
```sh | ||
extism-js index.js -i index.d.ts -o index.wasm | ||
``` | ||
This command compiles the TypeScript code in index.js into a WebAssembly module, ready for integration with the TLSNotary extension. | ||
|
||
### Running the Twitter Plugin Example: | ||
|
||
1. Build the `twitter_profile` plugin as explained above. | ||
2. Build and install the `tlsn-extension` as documented in the [main README.md](../README.md). | ||
3. [Run a local notary server](https://github.com/tlsnotary/tlsn/blob/main/notary-server/README.md), ensuring `TLS` is disabled in the [config file](https://github.com/tlsnotary/tlsn/blob/main/notary-server/config/config.yaml#L18). | ||
4. Install the plugin: Click the **Add a Plugin (+)** button and select the `index.wasm` file you built in step 1. A **Twitter Profile** button should then appear below the default buttons. | ||
5. Click the **Twitter Profile** button. This action opens the Twitter webpage along with a TLSNotary sidebar. | ||
6. Follow the steps in the TLSNotary sidebar. | ||
7. Access the TLSNotary results by clicking the **History** button in the TLSNotary extension. | ||
|
||
## Future Plugins | ||
|
||
This directory will be expanded with more plugins designed to demonstrate the functionality of the TLSNotary extension. Plugins enable flexible use of the TLSNotary across a broad range of applications. The use of Extism facilitates plugin development in various languages, further enhancing flexibility. | ||
|
||
## Create an icon | ||
|
||
1. resize to 320x320 pixels: | ||
```sh | ||
convert icon.png -resize 320x320! icon_320.png | ||
``` | ||
2. convert to base64 | ||
```sh | ||
base64 -i icon_320.png -o icon_320.txt | ||
``` |
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,4 @@ | ||
declare module 'main' { | ||
// Extism exports take no params and return an I32 | ||
export function hello(): I32; | ||
} |
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,6 @@ | ||
function hello() { | ||
const name = Host.inputString(); | ||
Host.outputString(`Hello, ${name}`); | ||
} | ||
|
||
module.exports = { hello }; |
Binary file not shown.
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,14 @@ | ||
declare module 'main' { | ||
// Extism exports take no params and return an I32 | ||
export function start(): I32; | ||
export function two(): I32; | ||
export function three(): I32; | ||
export function config(): I32; | ||
} | ||
|
||
declare module 'extism:host' { | ||
interface user { | ||
redirect(ptr: I64): void; | ||
notarize(ptr: I64): I64; | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
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,14 @@ | ||
declare module 'main' { | ||
// Extism exports take no params and return an I32 | ||
export function start(): I32; | ||
export function two(): I32; | ||
export function three(): I32; | ||
export function config(): I32; | ||
} | ||
|
||
declare module 'extism:host' { | ||
interface user { | ||
redirect(ptr: I64): void; | ||
notarize(ptr: I64): I64; | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,26 @@ | ||
import React, { ReactElement } from 'react'; | ||
import Modal, { ModalContent } from '../Modal/Modal'; | ||
|
||
export function ErrorModal(props: { | ||
onClose: () => void; | ||
message: string; | ||
}): ReactElement { | ||
const { onClose, message } = props; | ||
|
||
return ( | ||
<Modal | ||
className="flex flex-col gap-4 items-center text-base cursor-default justify-center !w-auto mx-4 my-[50%] min-h-24 p-4 border border-red-500 !bg-red-100" | ||
onClose={onClose} | ||
> | ||
<ModalContent className="flex justify-center items-center text-red-500"> | ||
{message || 'Something went wrong :('} | ||
</ModalContent> | ||
<button | ||
className="m-0 w-24 bg-red-200 text-red-400 hover:bg-red-200 hover:text-red-500" | ||
onClick={onClose} | ||
> | ||
OK | ||
</button> | ||
</Modal> | ||
); | ||
} |
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,23 @@ | ||
.plugin-box { | ||
&__remove-icon { | ||
opacity: 0; | ||
height: 0; | ||
width: 0; | ||
padding: 0; | ||
overflow: hidden; | ||
transition: 200ms opacity; | ||
} | ||
|
||
&:hover { | ||
.plugin-box__remove-icon { | ||
height: 1.25rem; | ||
width: 1.25rem; | ||
padding: .5rem; | ||
opacity: .5; | ||
|
||
&:hover { | ||
opacity: 1; | ||
} | ||
} | ||
} | ||
} |
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,113 @@ | ||
import React, { | ||
ChangeEvent, | ||
MouseEventHandler, | ||
ReactElement, | ||
useCallback, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
import { | ||
fetchPluginHashes, | ||
removePlugin, | ||
fetchPluginConfigByHash, | ||
runPlugin, | ||
} from '../../utils/rpc'; | ||
import { usePluginHashes } from '../../reducers/plugins'; | ||
import { PluginConfig } from '../../utils/misc'; | ||
import DefaultPluginIcon from '../../assets/img/default-plugin-icon.png'; | ||
import classNames from 'classnames'; | ||
import Icon from '../Icon'; | ||
import './index.scss'; | ||
import browser from 'webextension-polyfill'; | ||
import { ErrorModal } from '../ErrorModal'; | ||
|
||
export function PluginList(props: { className?: string }): ReactElement { | ||
const hashes = usePluginHashes(); | ||
|
||
useEffect(() => { | ||
fetchPluginHashes(); | ||
}, []); | ||
|
||
return ( | ||
<div className={classNames('flex flex-col flex-nowrap', props.className)}> | ||
{!hashes.length && ( | ||
<div className="flex flex-col items-center justify-center text-slate-400 cursor-default select-none"> | ||
<div>No available plugins</div> | ||
</div> | ||
)} | ||
{hashes.map((hash) => ( | ||
<Plugin key={hash} hash={hash} /> | ||
))} | ||
</div> | ||
); | ||
} | ||
|
||
export function Plugin(props: { | ||
hash: string; | ||
onClick?: () => void; | ||
}): ReactElement { | ||
const [error, showError] = useState(''); | ||
const [config, setConfig] = useState<PluginConfig | null>(null); | ||
|
||
const onClick = useCallback(async () => { | ||
if (!config) return; | ||
|
||
try { | ||
await runPlugin(props.hash, 'start'); | ||
|
||
const [tab] = await browser.tabs.query({ | ||
active: true, | ||
currentWindow: true, | ||
}); | ||
|
||
await browser.storage.local.set({ plugin_hash: props.hash }); | ||
|
||
// @ts-ignore | ||
if (chrome.sidePanel) await chrome.sidePanel.open({ tabId: tab.id }); | ||
|
||
window.close(); | ||
} catch (e: any) { | ||
showError(e.message); | ||
} | ||
}, [props.hash, config]); | ||
|
||
useEffect(() => { | ||
(async function () { | ||
setConfig(await fetchPluginConfigByHash(props.hash)); | ||
})(); | ||
}, [props.hash]); | ||
|
||
const onRemove: MouseEventHandler = useCallback( | ||
(e) => { | ||
e.stopPropagation(); | ||
removePlugin(props.hash); | ||
}, | ||
[props.hash], | ||
); | ||
|
||
if (!config) return <></>; | ||
|
||
return ( | ||
<button | ||
className={classNames( | ||
'flex flex-row border rounded border-slate-300 p-2 gap-2 plugin-box', | ||
'cursor-pointer hover:bg-slate-100 hover:border-slate-400 active:bg-slate-200', | ||
)} | ||
onClick={onClick} | ||
> | ||
{!!error && <ErrorModal onClose={() => showError('')} message={error} />} | ||
<img className="w-12 h-12" src={config.icon || DefaultPluginIcon} /> | ||
<div className="flex flex-col w-full items-start"> | ||
<div className="font-bold flex flex-row h-6 items-center justify-between w-full"> | ||
{config.title} | ||
<Icon | ||
fa="fa-solid fa-xmark" | ||
className="flex flex-row items-center justify-center cursor-pointer text-red-500 bg-red-200 rounded-full plugin-box__remove-icon" | ||
onClick={onRemove} | ||
/> | ||
</div> | ||
<div>{config.description}</div> | ||
</div> | ||
</button> | ||
); | ||
} |
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
Oops, something went wrong.