1- import {
2- isNumericTelegramUserId ,
3- normalizeTelegramAllowFromEntry ,
4- } from "../../extensions/telegram/src/allow-from.js" ;
51import {
62 hasConfiguredUnavailableCredentialStatus ,
73 hasResolvedCredentialValue ,
@@ -15,14 +11,18 @@ import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "../con
1511import type { OpenClawConfig } from "../config/config.js" ;
1612import { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js" ;
1713import { formatErrorMessage } from "../infra/errors.js" ;
18- import { readChannelAllowFromStore } from "../pairing/pairing-store.js" ;
1914import { normalizeStringEntries } from "../shared/string-normalization.js" ;
2015import type { SecurityAuditFinding , SecurityAuditSeverity } from "./audit.js" ;
2116import { resolveDmAllowState } from "./dm-policy-shared.js" ;
22- import {
23- isDiscordMutableAllowEntry ,
24- isZalouserMutableGroupEntry ,
25- } from "./mutable-allowlist-detectors.js" ;
17+
18+ let auditChannelRuntimeModulePromise :
19+ | Promise < typeof import ( "./audit-channel.runtime.js" ) >
20+ | undefined ;
21+
22+ function loadAuditChannelRuntimeModule ( ) {
23+ auditChannelRuntimeModulePromise ??= import ( "./audit-channel.runtime.js" ) ;
24+ return auditChannelRuntimeModulePromise ;
25+ }
2626
2727function normalizeAllowFromList ( list : Array < string | number > | undefined | null ) : string [ ] {
2828 return normalizeStringEntries ( Array . isArray ( list ) ? list : undefined ) ;
@@ -32,12 +32,13 @@ function addDiscordNameBasedEntries(params: {
3232 target : Set < string > ;
3333 values : unknown ;
3434 source : string ;
35+ isDiscordMutableAllowEntry : ( value : string ) => boolean ;
3536} ) : void {
3637 if ( ! Array . isArray ( params . values ) ) {
3738 return ;
3839 }
3940 for ( const value of params . values ) {
40- if ( ! isDiscordMutableAllowEntry ( String ( value ) ) ) {
41+ if ( ! params . isDiscordMutableAllowEntry ( String ( value ) ) ) {
4142 continue ;
4243 }
4344 const text = String ( value ) . trim ( ) ;
@@ -52,25 +53,28 @@ function addZalouserMutableGroupEntries(params: {
5253 target : Set < string > ;
5354 groups : unknown ;
5455 source : string ;
56+ isZalouserMutableGroupEntry : ( value : string ) => boolean ;
5557} ) : void {
5658 if ( ! params . groups || typeof params . groups !== "object" || Array . isArray ( params . groups ) ) {
5759 return ;
5860 }
5961 for ( const key of Object . keys ( params . groups as Record < string , unknown > ) ) {
60- if ( ! isZalouserMutableGroupEntry ( key ) ) {
62+ if ( ! params . isZalouserMutableGroupEntry ( key ) ) {
6163 continue ;
6264 }
6365 params . target . add ( `${ params . source } :${ key } ` ) ;
6466 }
6567}
6668
67- function collectInvalidTelegramAllowFromEntries ( params : {
69+ async function collectInvalidTelegramAllowFromEntries ( params : {
6870 entries : unknown ;
6971 target : Set < string > ;
70- } ) : void {
72+ } ) : Promise < void > {
7173 if ( ! Array . isArray ( params . entries ) ) {
7274 return ;
7375 }
76+ const { isNumericTelegramUserId, normalizeTelegramAllowFromEntry } =
77+ await loadAuditChannelRuntimeModule ( ) ;
7478 for ( const entry of params . entries ) {
7579 const normalized = normalizeTelegramAllowFromEntry ( entry ) ;
7680 if ( ! normalized || normalized === "*" ) {
@@ -383,6 +387,8 @@ export async function collectChannelSecurityFindings(params: {
383387 }
384388
385389 if ( plugin . id === "discord" ) {
390+ const { isDiscordMutableAllowEntry, readChannelAllowFromStore } =
391+ await loadAuditChannelRuntimeModule ( ) ;
386392 const discordCfg =
387393 ( account as { config ?: Record < string , unknown > } | null ) ?. config ??
388394 ( { } as Record < string , unknown > ) ;
@@ -401,16 +407,19 @@ export async function collectChannelSecurityFindings(params: {
401407 target : discordNameBasedAllowEntries ,
402408 values : discordCfg . allowFrom ,
403409 source : `${ discordPathPrefix } .allowFrom` ,
410+ isDiscordMutableAllowEntry,
404411 } ) ;
405412 addDiscordNameBasedEntries ( {
406413 target : discordNameBasedAllowEntries ,
407414 values : ( discordCfg . dm as { allowFrom ?: unknown } | undefined ) ?. allowFrom ,
408415 source : `${ discordPathPrefix } .dm.allowFrom` ,
416+ isDiscordMutableAllowEntry,
409417 } ) ;
410418 addDiscordNameBasedEntries ( {
411419 target : discordNameBasedAllowEntries ,
412420 values : storeAllowFrom ,
413421 source : "~/.openclaw/credentials/discord-allowFrom.json" ,
422+ isDiscordMutableAllowEntry,
414423 } ) ;
415424 const discordGuildEntries =
416425 ( discordCfg . guilds as Record < string , unknown > | undefined ) ?? { } ;
@@ -423,6 +432,7 @@ export async function collectChannelSecurityFindings(params: {
423432 target : discordNameBasedAllowEntries ,
424433 values : guild . users ,
425434 source : `${ discordPathPrefix } .guilds.${ guildKey } .users` ,
435+ isDiscordMutableAllowEntry,
426436 } ) ;
427437 const channels = guild . channels ;
428438 if ( ! channels || typeof channels !== "object" ) {
@@ -439,6 +449,7 @@ export async function collectChannelSecurityFindings(params: {
439449 target : discordNameBasedAllowEntries ,
440450 values : channel . users ,
441451 source : `${ discordPathPrefix } .guilds.${ guildKey } .channels.${ channelKey } .users` ,
452+ isDiscordMutableAllowEntry,
442453 } ) ;
443454 }
444455 }
@@ -547,6 +558,7 @@ export async function collectChannelSecurityFindings(params: {
547558 }
548559
549560 if ( plugin . id === "zalouser" ) {
561+ const { isZalouserMutableGroupEntry } = await loadAuditChannelRuntimeModule ( ) ;
550562 const zalouserCfg =
551563 ( account as { config ?: Record < string , unknown > } | null ) ?. config ??
552564 ( { } as Record < string , unknown > ) ;
@@ -560,6 +572,7 @@ export async function collectChannelSecurityFindings(params: {
560572 target : mutableGroupEntries ,
561573 groups : zalouserCfg . groups ,
562574 source : `${ zalouserPathPrefix } .groups` ,
575+ isZalouserMutableGroupEntry,
563576 } ) ;
564577 if ( mutableGroupEntries . size > 0 ) {
565578 const examples = Array . from ( mutableGroupEntries ) . slice ( 0 , 5 ) ;
@@ -586,6 +599,7 @@ export async function collectChannelSecurityFindings(params: {
586599 }
587600
588601 if ( plugin . id === "slack" ) {
602+ const { readChannelAllowFromStore } = await loadAuditChannelRuntimeModule ( ) ;
589603 const slackCfg =
590604 ( account as { config ?: Record < string , unknown > ; dm ?: Record < string , unknown > } | null )
591605 ?. config ?? ( { } as Record < string , unknown > ) ;
@@ -724,63 +738,66 @@ export async function collectChannelSecurityFindings(params: {
724738 continue ;
725739 }
726740
741+ const { readChannelAllowFromStore } = await loadAuditChannelRuntimeModule ( ) ;
727742 const storeAllowFrom = await readChannelAllowFromStore (
728743 "telegram" ,
729744 process . env ,
730745 accountId ,
731746 ) . catch ( ( ) => [ ] ) ;
732747 const storeHasWildcard = storeAllowFrom . some ( ( v ) => String ( v ) . trim ( ) === "*" ) ;
733748 const invalidTelegramAllowFromEntries = new Set < string > ( ) ;
734- collectInvalidTelegramAllowFromEntries ( {
749+ await collectInvalidTelegramAllowFromEntries ( {
735750 entries : storeAllowFrom ,
736751 target : invalidTelegramAllowFromEntries ,
737752 } ) ;
738753 const groupAllowFrom = Array . isArray ( telegramCfg . groupAllowFrom )
739754 ? telegramCfg . groupAllowFrom
740755 : [ ] ;
741756 const groupAllowFromHasWildcard = groupAllowFrom . some ( ( v ) => String ( v ) . trim ( ) === "*" ) ;
742- collectInvalidTelegramAllowFromEntries ( {
757+ await collectInvalidTelegramAllowFromEntries ( {
743758 entries : groupAllowFrom ,
744759 target : invalidTelegramAllowFromEntries ,
745760 } ) ;
746761 const dmAllowFrom = Array . isArray ( telegramCfg . allowFrom ) ? telegramCfg . allowFrom : [ ] ;
747- collectInvalidTelegramAllowFromEntries ( {
762+ await collectInvalidTelegramAllowFromEntries ( {
748763 entries : dmAllowFrom ,
749764 target : invalidTelegramAllowFromEntries ,
750765 } ) ;
751- const anyGroupOverride = Boolean (
752- groups &&
753- Object . values ( groups ) . some ( ( value ) => {
766+ let anyGroupOverride = false ;
767+ if ( groups ) {
768+ for ( const value of Object . values ( groups ) ) {
754769 if ( ! value || typeof value !== "object" ) {
755- return false ;
770+ continue ;
756771 }
757772 const group = value as Record < string , unknown > ;
758773 const allowFrom = Array . isArray ( group . allowFrom ) ? group . allowFrom : [ ] ;
759774 if ( allowFrom . length > 0 ) {
760- collectInvalidTelegramAllowFromEntries ( {
775+ anyGroupOverride = true ;
776+ await collectInvalidTelegramAllowFromEntries ( {
761777 entries : allowFrom ,
762778 target : invalidTelegramAllowFromEntries ,
763779 } ) ;
764- return true ;
765780 }
766781 const topics = group . topics ;
767782 if ( ! topics || typeof topics !== "object" ) {
768- return false ;
783+ continue ;
769784 }
770- return Object . values ( topics as Record < string , unknown > ) . some ( ( topicValue ) => {
785+ for ( const topicValue of Object . values ( topics as Record < string , unknown > ) ) {
771786 if ( ! topicValue || typeof topicValue !== "object" ) {
772- return false ;
787+ continue ;
773788 }
774789 const topic = topicValue as Record < string , unknown > ;
775790 const topicAllow = Array . isArray ( topic . allowFrom ) ? topic . allowFrom : [ ] ;
776- collectInvalidTelegramAllowFromEntries ( {
791+ if ( topicAllow . length > 0 ) {
792+ anyGroupOverride = true ;
793+ }
794+ await collectInvalidTelegramAllowFromEntries ( {
777795 entries : topicAllow ,
778796 target : invalidTelegramAllowFromEntries ,
779797 } ) ;
780- return topicAllow . length > 0 ;
781- } ) ;
782- } ) ,
783- ) ;
798+ }
799+ }
800+ }
784801
785802 const hasAnySenderAllowlist =
786803 storeAllowFrom . length > 0 || groupAllowFrom . length > 0 || anyGroupOverride ;
0 commit comments