mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-16 16:28:50 +00:00
plugin docs
This commit is contained in:
86
docs/plugins.md
Normal file
86
docs/plugins.md
Normal file
@ -0,0 +1,86 @@
|
||||
# Write policy plugins
|
||||
|
||||
In order to reduce complexity, strfry's design attempts to keep policy logic out of its core relay functionality. Instead, this logic can be implemented by operators by installing a write policy plugin. Among other things, plugins can be used for the following:
|
||||
|
||||
* White/black-lists (particular pubkeys can/can't post events)
|
||||
* Rate-limits
|
||||
* Spam filtering
|
||||
|
||||
A plugin can be implemented in any programming language that supports reading lines from stdin, decoding JSON, and printing JSON to stdout. If a plugin is installed, strfry will send the event (along with some other information like IP address) to the plugin over stdin. The plugin should then decide what to do with it and print out a JSON object containing this decision.
|
||||
|
||||
Whenever the script's modification-time changes, or the plugin settings in `strfry.conf` change, the plugin will be reloaded upon the next write attempt.
|
||||
|
||||
If configured, When a plugin is loaded some number of recently stored events will be sent to it as a "lookback". This is useful for populating the initial rate-limiting state. Plugins should print nothing in response to a lookback message.
|
||||
|
||||
|
||||
## Input messages
|
||||
|
||||
Input messages contain the following keys:
|
||||
|
||||
* `type`: Either `new` or `lookback`
|
||||
* `event`: The event posted by the client, with all the required fields such as `id`, `pubkey`, etc
|
||||
* `receivedAt`: Unix timestamp of when this event was received by the relay
|
||||
* `sourceType`: Where this event came from. Typically will be `IP4` or `IP6`, but in lookback can also be `Import`, `Stream`, or `Sync`.
|
||||
* `sourceInfo`: Specifics of the event's source. Either an IP address or a relay URL (for stream/sync)
|
||||
|
||||
|
||||
## Output messages
|
||||
|
||||
In response to `new` events, the plugin should print a JSONL message (minified JSON followed by a newline). It should contain the following keys:
|
||||
|
||||
* `id`: The event ID taken from the `event.id` field of the input message
|
||||
* `action`: Either `accept`, `reject`, or `rejectShadow`
|
||||
* `msg`: The NIP-20 response message to be sent to the client. Only used for `reject`
|
||||
|
||||
|
||||
## Example: Whitelist
|
||||
|
||||
Here is a simple example `whitelist.js` plugin that will reject all events except for those in a whitelist:
|
||||
|
||||
#!/usr/bin/env node
|
||||
|
||||
const whiteList = {
|
||||
'003ba9b2c5bd8afeed41a4ce362a8b7fc3ab59c25b6a1359cae9093f296dac01': true,
|
||||
};
|
||||
|
||||
const rl = require('readline').createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
terminal: false
|
||||
});
|
||||
|
||||
rl.on('line', (line) => {
|
||||
let req = JSON.parse(line);
|
||||
|
||||
if (req.type === 'lookback') {
|
||||
return; // do nothing
|
||||
}
|
||||
|
||||
if (req.type !== 'new') {
|
||||
console.error("unexpected request type"); // will appear in strfry logs
|
||||
return;
|
||||
}
|
||||
|
||||
let res = { id: req.event.id }; // must echo the event's id
|
||||
|
||||
if (whiteList[req.event.pubkey]) {
|
||||
res.action = 'accept';
|
||||
} else {
|
||||
res.action = 'reject';
|
||||
res.msg = 'blocked: not on white-list';
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(res));
|
||||
});
|
||||
|
||||
To install:
|
||||
|
||||
* Make the script executable: `chmod a+x whitelist.js`
|
||||
* In `strfry.conf`, configure `relay.writePolicy.plugin` to `./whitelist.js`
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
* If applicable, you should ensure stdout is *line buffered* (for example, in perl use `$|++`).
|
||||
* If events are being rejected with `error: internal error`, then check the strfry logs. The plugin is misconfigured or failing.
|
||||
* When returning an action of `accept`, it doesn't necessarily guarantee that the event will be accepted. The regular strfry checks are still subsequently applied, such as expiration, deletion, etc.
|
@ -174,7 +174,7 @@ struct PluginWritePolicy {
|
||||
) throw herr("posix_span_file_actions failed: ", strerror(errno));
|
||||
|
||||
auto ret = posix_spawn(&pid, path.c_str(), &file_actions, nullptr, argv, nullptr);
|
||||
if (ret) throw herr("posix_spawn failed when to invoke '", path, "': ", strerror(errno));
|
||||
if (ret) throw herr("posix_spawn failed to invoke '", path, "': ", strerror(errno));
|
||||
|
||||
running = make_unique<RunningPlugin>(pid, inPipe.saveFd(0), outPipe.saveFd(1), path, cfg().relay__writePolicy__lookbackSeconds);
|
||||
}
|
||||
|
Reference in New Issue
Block a user