clawgram 2.21.0 → 2.22.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/README.md CHANGED
@@ -18,9 +18,9 @@ Clawgram is a personal-Telegram channel plugin for [OpenClaw](https://github.com
18
18
  > it can read private and group conversations within its configured scope and send messages that are
19
19
  > indistinguishable from ones you typed yourself. Recipients cannot tell an assistant reply from a
20
20
  > human one. Treat the account as compromised-if-leaked: `apiHash` and `sessionString` are bearer
21
- > credentials for everything that account can reach. Scope reads with `readChats`, gate senders with
22
- > `allowFrom`, and prefer a dedicated account over your primary one — see
23
- > [Security and privacy](#security-and-privacy).
21
+ > credentials for everything that account can reach. Scope reads with `readChats`, scope sends with
22
+ > `sendChats`, gate senders with `allowFrom`, and prefer a dedicated account over your primary one —
23
+ > see [Security and privacy](#security-and-privacy).
24
24
 
25
25
 
26
26
  ## Features
@@ -184,6 +184,13 @@ openclaw gateway restart
184
184
  openclaw gateway restart
185
185
  ```
186
186
 
187
+ **What `--auth` writes is closed, on purpose.** The first config allows only the
188
+ account that authorised (`allowFrom: [<your id>]`), seeds no group entry, and
189
+ writes `readChats: []`. Until 2.21.1 it seeded `allowFrom: ["*"]` with an
190
+ enabled wildcard group, so a freshly authorised account answered any Telegram
191
+ user and read the history of every chat it belonged to. Widen both lists
192
+ deliberately; the flow prints who can reach the agent before it exits.
193
+
187
194
  One restart after installation is enough. From 2.17.0 the plugin declares
188
195
  `channels.clawgram` as a hot-reloadable prefix, so later edits under it —
189
196
  `allowFrom`, `groups`, `readChats`, proxy — are picked up by the Gateway's
@@ -249,6 +256,7 @@ loud where it does occur.
249
256
  | `apiHash` | string | required | Telegram API hash |
250
257
  | `sessionString` | string | `""` | Authenticated StringSession |
251
258
  | `allowFrom` | string[] | `["*"]` | Allowed sender IDs/usernames for direct messages only. Three states: absent means everyone, `[]` denies everyone (a warning is logged at account start), a list allows those senders |
259
+ | `operatorIds` | string[] | — | Who receives core's operational telemetry in a DM (tool-failure warnings, fallback notices). They quote shell commands and secret-store paths, so they go only to these ids. Absent falls back to `allowFrom` when it is a concrete list; a wildcard or an empty list means no operator is identified and the notices are dropped everywhere — they stay in the run diagnostics and the gateway log |
252
260
  | `groups` | object | `{}` | Allowed groups map keyed by explicit group id or `*` |
253
261
  | `proxy` | object | unset | Optional SOCKS4/SOCKS5 proxy for this account — see [Proxy (SOCKS4/SOCKS5)](#proxy-socks4socks5) |
254
262
  | `manageChats` | string[] | unset | Chats the assistant may **manage** — see [Chat management](#chat-management). Absent or empty = management off; `["*"]` = every chat |
@@ -809,10 +817,27 @@ nothing is not an error — it says which nothing it was:
809
817
  A reading that fails while the download succeeded still returns `ok: true`, with `readError` beside
810
818
  the path: the bytes are already there and can still be forwarded.
811
819
 
812
- **Fetched files live in the system temp directory** (`clawgram-fetched/`), named after the chat and
813
- message they came from, and are pruned after 24 hours by the next fetch. Nothing else removes them,
814
- and nothing sends them anywhere putting a fetched file in a chat is an ordinary `upload-file`,
815
- with whatever confirmation the deployment requires for that.
820
+ **Fetched files live under the OpenClaw state directory** (`$OPENCLAW_STATE_DIR/tmp/clawgram-fetched/`,
821
+ falling back to the system temp directory when that variable is unset), named after the chat and
822
+ message they came from, and are pruned an hour later by the next fetch. The directory is created
823
+ 0700 and each file written 0600: these are private-chat images and voice notes, and until 2.21.1
824
+ they sat in a shared `/tmp` at 0644 for a day, readable by every local account on the host. Nothing
825
+ else removes them, and nothing sends them anywhere — putting a fetched file in a chat is an ordinary
826
+ `upload-file`, with whatever confirmation the deployment requires for that.
827
+
828
+ ## Dependencies are pinned, and the lock ships
829
+
830
+ `installDependencies: true` tells OpenClaw to run an install in the plugin
831
+ directory, so what lands on the host is whatever the registry serves that day —
832
+ and the MTProto client sees `apiHash`, `sessionString`, the proxy credentials
833
+ and every message. Since 2.21.1 the two runtime dependencies are pinned to
834
+ exact versions and `npm-shrinkwrap.json` is part of the published tarball, so an
835
+ install reproduces the tree the tests ran against rather than resolving a caret
836
+ range. `npm ci --ignore-scripts` verifies it.
837
+
838
+ The transitive `ip-address` is held at 10.7.0 through `overrides`: everything at
839
+ or below 10.3.0 carries three advisories about SSRF and trust-boundary bypass,
840
+ and it sits under the SOCKS proxy path this channel uses.
816
841
 
817
842
  ## Security and privacy
818
843
 
@@ -825,9 +850,10 @@ that means in practice, and what the code does about it:
825
850
  | Proxy password | `accounts.*.proxy.password`, or a secret store | Also accepts a SecretRef since 2.2.0. Marked `sensitive` in `uiHints`; diagnostics say `socks4`/`socks5` and nothing more. An invalid proxy fails the account rather than falling back to a direct connection, which would leak the host IP to Telegram |
826
851
  | Message bodies | channel logs | **Not logged.** Outbound sends record recipient, ids and `textLength`. Until 2.1.0 the full outbound text was written to the channel log — if you ran 2.0.x, treat those journal entries as containing private correspondence |
827
852
  | Read scope | `accounts.*.readChats` | History, membership and attachment fetches are confined to the listed chats. Absent means no restriction; an empty array denies everything. Telegram's own service chat (`777000`, where login codes arrive) is refused unconditionally, including under a wildcard |
853
+ | Send scope | `accounts.*.sendChats` | `send`, `upload-file`, `react` and core's delivery path are confined to the listed chats. Same shape as `readChats`: absent means no restriction, `[]` denies everything, `["*"]` allows every chat. **A phone number is refused whatever the list says** — messaging a raw number starts a conversation with someone who never contacted the account. Without the list, an injected turn can write to strangers from the owner's account or move a work chat's content into a DM one send at a time (2.22.0) |
828
854
  | Manage scope | `accounts.*.manageChats` | Creating groups, changing membership, admin rights, ownership and invite links are confined to the listed chats — and **off entirely** when the key is absent or empty (opposite default to `readChats`, because these actions change chats rather than read them) |
829
855
  | 2FA password | `accounts.*.twoFaPassword`, or a secret store | Read only by `transferOwnership`, exchanged for an SRP proof in-process. Accepts a SecretRef since 2.12.0; `sensitive` in `uiHints`; on the forbidden-log-keys list the static tests enforce |
830
- | Who may talk to it | `allowFrom`, `groups.*.groupPolicy` | Direct-message senders and group behaviour are allowlisted; `mention` limits group replies to explicit mentions |
856
+ | Who may talk to it | `allowFrom`, `groups.*.groupPolicy` | Direct-message senders and group behaviour are allowlisted; `mention` limits group replies to explicit mentions. **Write ids, not handles:** an `@username` entry is a claim about a handle, and a released handle can be taken by someone else, after which the entry admits a stranger. The account logs a warning at start-up for every handle entry (2.22.0) |
831
857
 
832
858
  Two static tests (`test/no-secret-logging.test.ts`) fail the build if a message body or a credential
833
859
  is ever added back to a log call, or if the auth flow prints the session string unprompted.