telegram-approval-buttons 4.0.3 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +1 -1
- package/SECURITY.md +39 -0
- package/index.ts +2 -2
- package/lib/approval-parser.ts +41 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.1.0] - 2026-02-20
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Performance: O(1) approval resolution lookup** — `detectApprovalResult()` now extracts UUIDs via regex and performs a direct `Map.has()` lookup instead of iterating all pending entries. The old O(n) linear scan is replaced with O(1) hash lookup for full UUIDs, with a fallback prefix scan only for truncated IDs.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Gateway denial detection** — New `resolveAction()` function and `RE_GATEWAY_DENIAL` regex detect when the gateway auto-denies an approval due to timeout (`Exec denied.*approval-timeout`). The plugin now immediately cleans up stale Telegram buttons when the gateway reports a timeout, instead of waiting for the stale cleanup timer.
|
|
15
|
+
- **Robust short hex matching** — Short approval IDs are now matched via `\b([a-f0-9]{8,})\b` regex with `startsWith()` prefix matching, supporting variable-length truncated IDs instead of the previous hardcoded 8-char `slice()`.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Synced `openclaw.plugin.json` manifest version with `package.json` (was stuck at 4.0.2)
|
|
19
|
+
- Updated header comment in `index.ts` to reflect current version
|
|
20
|
+
|
|
21
|
+
## [4.0.3] - 2026-02-16
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Auto-detect `botToken` key from `channels.telegram.botToken` in addition to `channels.telegram.token`
|
|
25
|
+
- Improved README setup documentation with clearer quick start instructions
|
|
26
|
+
|
|
8
27
|
## [4.0.2] - 2026-02-15
|
|
9
28
|
|
|
10
29
|
### Added
|
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ Uptime: 1m
|
|
|
114
114
|
## Prerequisites
|
|
115
115
|
|
|
116
116
|
- **OpenClaw ≥ 2026.2.9** installed and running
|
|
117
|
-
- **Node.js ≥
|
|
117
|
+
- **Node.js ≥ 20** (uses built-in `fetch`)
|
|
118
118
|
- **Telegram configured** in your `openclaw.json` (bot token + `allowFrom`)
|
|
119
119
|
- **Exec approvals targeting Telegram** — see Step 2 above
|
|
120
120
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
|---------|-----------|
|
|
7
|
+
| 4.x | ✅ Active |
|
|
8
|
+
| < 4.0 | ❌ EOL |
|
|
9
|
+
|
|
10
|
+
## Reporting a Vulnerability
|
|
11
|
+
|
|
12
|
+
If you discover a security vulnerability in this plugin, please report it responsibly:
|
|
13
|
+
|
|
14
|
+
1. **Do NOT open a public issue** — this could expose the vulnerability to others
|
|
15
|
+
2. **Email**: [francojair81@gmail.com](mailto:francojair81@gmail.com)
|
|
16
|
+
3. **Include**:
|
|
17
|
+
- Description of the vulnerability
|
|
18
|
+
- Steps to reproduce
|
|
19
|
+
- Potential impact
|
|
20
|
+
- Suggested fix (if you have one)
|
|
21
|
+
|
|
22
|
+
I will acknowledge your report within **48 hours** and aim to release a fix within **7 days** for critical issues.
|
|
23
|
+
|
|
24
|
+
## Security Model
|
|
25
|
+
|
|
26
|
+
This plugin runs **in-process** with the OpenClaw Gateway as trusted code:
|
|
27
|
+
|
|
28
|
+
- **No external network calls** except to the Telegram Bot API (`api.telegram.org`)
|
|
29
|
+
- **No data persistence** — all approval state is in-memory and lost on restart
|
|
30
|
+
- **No credential storage** — bot token and chat ID are read from OpenClaw's config at runtime
|
|
31
|
+
- **Input validation** — callback query data is validated against the pending approvals map; unknown IDs are silently ignored
|
|
32
|
+
- **HTML escaping** — all user-supplied text is escaped before Telegram HTML rendering to prevent injection
|
|
33
|
+
|
|
34
|
+
## Best Practices for Users
|
|
35
|
+
|
|
36
|
+
- Keep your OpenClaw instance and this plugin updated
|
|
37
|
+
- Use `plugins.allow` allowlists to restrict which plugins can load
|
|
38
|
+
- Review the source code before installing any community plugin
|
|
39
|
+
- Never share your bot token or chat ID publicly
|
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
-
// telegram-approval-buttons · index.ts (v4.0
|
|
2
|
+
// telegram-approval-buttons · index.ts (v4.1.0)
|
|
3
3
|
// Plugin entry point — orchestration only, all logic lives in lib/
|
|
4
4
|
//
|
|
5
5
|
// Adds inline keyboard buttons to exec approval messages in Telegram.
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
|
|
31
31
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
-
const PLUGIN_VERSION = "4.0
|
|
33
|
+
const PLUGIN_VERSION = "4.1.0";
|
|
34
34
|
const TAG = "telegram-approval-buttons";
|
|
35
35
|
|
|
36
36
|
// ── Plugin registration ─────────────────────────────────────────────────────
|
package/lib/approval-parser.ts
CHANGED
|
@@ -9,6 +9,9 @@ import type { ApprovalAction, ApprovalInfo, ApprovalResolution, SentApproval } f
|
|
|
9
9
|
|
|
10
10
|
const RE_APPROVAL_MARKER = /Exec approval required/i;
|
|
11
11
|
const RE_ID = /ID:\s*([a-f0-9-]+)/i;
|
|
12
|
+
const RE_UUID = /([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i;
|
|
13
|
+
const RE_SHORT_HEX = /\b([a-f0-9]{8,})\b/i;
|
|
14
|
+
const RE_GATEWAY_DENIAL = /Exec denied.*approval-timeout/i;
|
|
12
15
|
const RE_COMMAND_BLOCK = /Command:\s*`{0,3}\n?(.+?)\n?`{0,3}(?:\n|$)/is;
|
|
13
16
|
const RE_COMMAND_INLINE = /Command:\s*(.+)/i;
|
|
14
17
|
const RE_CWD = /CWD:\s*(.+)/i;
|
|
@@ -50,25 +53,56 @@ export function parseApprovalText(text: string): ApprovalInfo | null {
|
|
|
50
53
|
/**
|
|
51
54
|
* Detect if an outgoing message indicates an approval was resolved.
|
|
52
55
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
56
|
+
* Uses O(1) Map lookup instead of iterating all pending entries:
|
|
57
|
+
* 1. Extract full UUID from text via regex → direct Map.has() (O(1))
|
|
58
|
+
* 2. Fallback: extract short hex ID (8+ chars) → scan pending by prefix
|
|
59
|
+
*
|
|
60
|
+
* Also detects gateway-initiated denials (approval-timeout) so the
|
|
61
|
+
* plugin can immediately clean up stale buttons in Telegram.
|
|
55
62
|
*/
|
|
56
63
|
export function detectApprovalResult(
|
|
57
64
|
text: string,
|
|
58
65
|
pending: ReadonlyMap<string, SentApproval>,
|
|
59
66
|
): ApprovalResolution | null {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
if (pending.size === 0) return null;
|
|
68
|
+
|
|
69
|
+
// Fast path: full UUID → O(1) Map lookup
|
|
70
|
+
const fullMatch = text.match(RE_UUID);
|
|
71
|
+
if (fullMatch) {
|
|
72
|
+
const id = fullMatch[1];
|
|
73
|
+
if (pending.has(id)) {
|
|
74
|
+
return { id, action: resolveAction(text) };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
// Slow path: short hex ID (8+ chars) → prefix scan on pending keys
|
|
79
|
+
// This handles messages that only reference a truncated approval ID
|
|
80
|
+
const shortMatch = text.match(RE_SHORT_HEX);
|
|
81
|
+
if (shortMatch) {
|
|
82
|
+
const shortId = shortMatch[1];
|
|
83
|
+
for (const [pendingId] of pending) {
|
|
84
|
+
if (pendingId.startsWith(shortId)) {
|
|
85
|
+
return { id: pendingId, action: resolveAction(text) };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
66
88
|
}
|
|
89
|
+
|
|
67
90
|
return null;
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
// ─── Internal ───────────────────────────────────────────────────────────────
|
|
71
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Determine the approval action from message text.
|
|
97
|
+
* Checks gateway denial first, then infers from keywords.
|
|
98
|
+
* Order matters: check most specific patterns first.
|
|
99
|
+
*/
|
|
100
|
+
function resolveAction(text: string): ApprovalAction {
|
|
101
|
+
// Gateway-initiated denial takes priority (unambiguous signal)
|
|
102
|
+
if (RE_GATEWAY_DENIAL.test(text)) return "deny";
|
|
103
|
+
return inferAction(text);
|
|
104
|
+
}
|
|
105
|
+
|
|
72
106
|
/**
|
|
73
107
|
* Infer the approval action from message text.
|
|
74
108
|
* Order matters: check most specific patterns first.
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "telegram-approval-buttons",
|
|
3
3
|
"name": "Telegram Approval Buttons",
|
|
4
4
|
"description": "Adds inline keyboard buttons to exec approval messages in Telegram. Tap to approve/deny without typing commands.",
|
|
5
|
-
"version": "4.0
|
|
5
|
+
"version": "4.1.0",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telegram-approval-buttons",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Inline keyboard buttons for exec approval messages in Telegram — tap to approve/deny without typing commands",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20.0.0"
|
|
10
|
+
},
|
|
8
11
|
"scripts": {
|
|
9
12
|
"test": "vitest run",
|
|
10
13
|
"test:watch": "vitest"
|
|
@@ -34,7 +37,8 @@
|
|
|
34
37
|
"lib/",
|
|
35
38
|
"openclaw.plugin.json",
|
|
36
39
|
"README.md",
|
|
37
|
-
"CHANGELOG.md"
|
|
40
|
+
"CHANGELOG.md",
|
|
41
|
+
"SECURITY.md"
|
|
38
42
|
],
|
|
39
43
|
"devDependencies": {
|
|
40
44
|
"@types/node": "^25.2.3",
|