@m1a0rz/agent-identity 0.3.2 → 0.3.3

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.
Files changed (40) hide show
  1. package/dist/index.js +5 -5
  2. package/dist/src/actions/identity-actions.d.ts.map +1 -1
  3. package/dist/src/actions/identity-actions.js +7 -2
  4. package/dist/src/commands/identity-commands.js +2 -2
  5. package/dist/src/hooks/before-agent-start.js +1 -1
  6. package/dist/src/hooks/before-tool-call.js +4 -4
  7. package/dist/src/hooks/llm-input.js +3 -3
  8. package/dist/src/hooks/sessions-send-propagation.js +1 -1
  9. package/dist/src/hooks/sessions-spawn-propagation.js +1 -1
  10. package/dist/src/hooks/subagent-ended-cleanup.js +1 -1
  11. package/dist/src/routes/oidc-login.d.ts.map +1 -1
  12. package/dist/src/routes/oidc-login.js +49 -7
  13. package/dist/src/services/identity-service.d.ts +3 -2
  14. package/dist/src/services/identity-service.d.ts.map +1 -1
  15. package/dist/src/services/identity-service.js +3 -2
  16. package/dist/src/services/oidc-client.d.ts +25 -8
  17. package/dist/src/services/oidc-client.d.ts.map +1 -1
  18. package/dist/src/services/oidc-client.js +55 -1
  19. package/dist/src/services/session-refresh.d.ts.map +1 -1
  20. package/dist/src/services/session-refresh.js +11 -2
  21. package/dist/src/store/oidc-state-store.d.ts +8 -1
  22. package/dist/src/store/oidc-state-store.d.ts.map +1 -1
  23. package/dist/src/store/oidc-state-store.js +3 -1
  24. package/dist/src/store/{group-sender-store.d.ts → sender-session-store.d.ts} +14 -7
  25. package/dist/src/store/sender-session-store.d.ts.map +1 -0
  26. package/dist/src/store/{group-sender-store.js → sender-session-store.js} +41 -12
  27. package/dist/src/tools/identity-approve-tool.js +1 -1
  28. package/dist/src/tools/identity-fetch.js +1 -1
  29. package/dist/src/tools/identity-list-credentials.js +1 -1
  30. package/dist/src/tools/identity-login.js +1 -1
  31. package/dist/src/tools/identity-logout.js +1 -1
  32. package/dist/src/tools/identity-set-binding.js +1 -1
  33. package/dist/src/tools/identity-status.js +1 -1
  34. package/dist/src/tools/identity-unset-binding.js +1 -1
  35. package/dist/src/tools/identity-whoami.js +1 -1
  36. package/dist/src/utils/derive-session-key.d.ts +34 -4
  37. package/dist/src/utils/derive-session-key.d.ts.map +1 -1
  38. package/dist/src/utils/derive-session-key.js +50 -5
  39. package/package.json +4 -3
  40. package/dist/src/store/group-sender-store.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -19,8 +19,8 @@ import { createLlmInputHandler } from "./src/hooks/llm-input.js";
19
19
  import { createSessionsSendPropagationHandler } from "./src/hooks/sessions-send-propagation.js";
20
20
  import { createSessionsSpawnPropagationHandler } from "./src/hooks/sessions-spawn-propagation.js";
21
21
  import { createSubagentEndedCleanupHandler } from "./src/hooks/subagent-ended-cleanup.js";
22
- import { setSender, clearSender } from "./src/store/group-sender-store.js";
23
- import { deriveSessionKey, isGroupOrChannelSessionKey, } from "./src/utils/derive-session-key.js";
22
+ import { setSender, clearSender } from "./src/store/sender-session-store.js";
23
+ import { deriveSessionKey, needsSenderIsolation, } from "./src/utils/derive-session-key.js";
24
24
  import { createBeforeToolCallHandler } from "./src/hooks/before-tool-call.js";
25
25
  import { createAfterToolCallHandler } from "./src/hooks/after-tool-call.js";
26
26
  import * as skillPathStore from "./src/store/skill-path-store.js";
@@ -43,7 +43,7 @@ import { createIdentityStatusTool } from "./src/tools/identity-status.js";
43
43
  import { createIdentityUnsetBindingTool } from "./src/tools/identity-unset-binding.js";
44
44
  import { createIdentityWhoamiTool } from "./src/tools/identity-whoami.js";
45
45
  import { parseSessionKeyToDeliveryTarget, } from "./src/utils/derive-session-key.js";
46
- import { logInfo, logWarn } from "./src/utils/logger.js";
46
+ import { logDebug, logInfo, logWarn } from "./src/utils/logger.js";
47
47
  import { initEncryptionKey } from "./src/store/encryption.js";
48
48
  const PLUGIN_STORE_DIR = "~/.openclaw/plugins/identity";
49
49
  /**
@@ -323,7 +323,7 @@ export default function register(api) {
323
323
  accountId: ctx.accountId,
324
324
  config: api.runtime.config.loadConfig(),
325
325
  });
326
- if (!sessionKey || !isGroupOrChannelSessionKey(sessionKey))
326
+ if (!sessionKey || !needsSenderIsolation(sessionKey))
327
327
  return;
328
328
  setSender(sessionKey, {
329
329
  senderId,
@@ -333,7 +333,7 @@ export default function register(api) {
333
333
  messageId: metadata?.messageId,
334
334
  capturedAt: Date.now(),
335
335
  });
336
- logInfo(api.logger, `group sender captured session=${sessionKey} sender=${senderId}`);
336
+ logDebug(api.logger, `sender captured session=${sessionKey} sender=${senderId}`);
337
337
  }, { priority: 200 });
338
338
  api.on("session_end", (_event, ctx) => {
339
339
  if (ctx.sessionKey)
@@ -1 +1 @@
1
- {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { logDebug, logInfo, logWarn } from "../utils/logger.js";
17
17
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
18
- import { fetchOIDCDiscovery, buildAuthorizationUrl, generateState, } from "../services/oidc-client.js";
18
+ import { fetchOIDCDiscovery, buildAuthorizationUrl, generateState, generatePKCE, generateNonce, } from "../services/oidc-client.js";
19
19
  import { loadCredentialEnvBindings, loadAllCredentialEnvBindings, setCredentialEnvBinding, deleteCredentialEnvBinding, } from "../store/credential-env-bindings.js";
20
20
  import { loadCredentials, setCredential, getCredential, deleteCredentialsForSession, } from "../store/credential-store.js";
21
21
  import { getSession, deleteSession } from "../store/session-store.js";
@@ -134,13 +134,18 @@ export async function runLogin(deps, sessionKey, options) {
134
134
  const oidcConfig = await getOidcConfig();
135
135
  const discovery = await fetchOIDCDiscovery(oidcConfig.discoveryUrl);
136
136
  const state = await generateState();
137
- await createState(storeDir, sessionKey, "", state, deliveryTarget);
137
+ const { codeVerifier, codeChallenge } = await generatePKCE();
138
+ const nonce = await generateNonce();
139
+ await createState(storeDir, sessionKey, "", state, deliveryTarget, { codeVerifier, nonce });
138
140
  const authUrl = buildAuthorizationUrl({
139
141
  authorizationEndpoint: discovery.authorization_endpoint,
140
142
  clientId: oidcConfig.clientId,
141
143
  redirectUri: oidcConfig.callbackUrl,
142
144
  scope: oidcConfig.scope ?? "openid profile email offline_access",
143
145
  state,
146
+ codeChallenge,
147
+ codeChallengeMethod: "S256",
148
+ nonce,
144
149
  });
145
150
  logInfo(logger, `login returning IdP URL for sessionKey=${sessionKey.slice(0, 24)}...`);
146
151
  return { kind: "auth_url", authUrl };
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { runStatus, runLogin, runLogout, runListCredentials, runListTips, runConfig, runFetch, runSetBinding, runUnsetBinding, } from "../actions/identity-actions.js";
17
17
  import { deriveSessionKey, deriveDeliveryTargetFromContext, } from "../utils/derive-session-key.js";
18
- import { buildEffectiveSessionKey } from "../store/group-sender-store.js";
18
+ import { buildEffectiveSessionKey } from "../store/sender-session-store.js";
19
19
  import { logDebug } from "../utils/logger.js";
20
20
  import { diagnoseRisk } from "../risk/diagnose-risk.js";
21
21
  import { getRiskPatterns } from "../risk/classify-risk.js";
@@ -169,7 +169,7 @@ function createIdentityHandler(deps) {
169
169
  config: ctx.config,
170
170
  });
171
171
  const sessionKey = baseSessionKey
172
- ? buildEffectiveSessionKey(baseSessionKey, ctx.senderId)
172
+ ? buildEffectiveSessionKey(baseSessionKey, ctx.senderId, ctx.channel)
173
173
  : null;
174
174
  const needsSession = [
175
175
  "login",
@@ -16,7 +16,7 @@
16
16
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
17
17
  import { logDebug, logWarn } from "../utils/logger.js";
18
18
  import { isSubagentSessionKey } from "../utils/derive-session-key.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createBeforeAgentStartHandler(deps) {
21
21
  const { storeDir, identityService, configWorkloadName, getOidcConfigForRefresh, logger } = deps;
22
22
  const tipRefreshOptions = {
@@ -23,9 +23,9 @@ import { applyEnvSnapshot } from "../store/credential-env-snapshot.js";
23
23
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
24
24
  import { supportsSyncApproval } from "../utils/approval-channel.js";
25
25
  import { extractDelegationChainFromJwt } from "../utils/auth.js";
26
- import { isSubagentSessionKey, isGroupOrChannelSessionKey } from "../utils/derive-session-key.js";
26
+ import { isSubagentSessionKey, needsSenderIsolation } from "../utils/derive-session-key.js";
27
27
  import { LOG_PREFIX, logDebug, logWarn } from "../utils/logger.js";
28
- import { getSender, resolveEffectiveSessionKeyForRun } from "../store/group-sender-store.js";
28
+ import { getSender, resolveEffectiveSessionKeyForRun } from "../store/sender-session-store.js";
29
29
  // ─── Exempt tools (bypass session + authz entirely) ──────────────────
30
30
  const IDENTITY_EXEMPT_TOOLS = new Set([
31
31
  "identity_login",
@@ -98,8 +98,8 @@ export function createBeforeToolCallHandler(deps) {
98
98
  if (!sessionKey)
99
99
  return;
100
100
  const effectiveKey = resolveEffectiveSessionKeyForRun(sessionKey, event.runId);
101
- // Phase 1: group sender context
102
- if (isGroupOrChannelSessionKey(sessionKey)) {
101
+ // Phase 1: sender context for shared sessions (group/channel and default main)
102
+ if (needsSenderIsolation(sessionKey)) {
103
103
  const groupSender = getSender(sessionKey);
104
104
  if (groupSender) {
105
105
  params._enhancedContext = {
@@ -20,15 +20,15 @@
20
20
  */
21
21
  import { parseAvailableSkills } from "../utils/parse-available-skills.js";
22
22
  import * as skillPathStore from "../store/skill-path-store.js";
23
- import { freezeRun, resolveEffectiveSessionKey } from "../store/group-sender-store.js";
24
- import { isGroupOrChannelSessionKey } from "../utils/derive-session-key.js";
23
+ import { freezeRun, resolveEffectiveSessionKey } from "../store/sender-session-store.js";
24
+ import { needsSenderIsolation } from "../utils/derive-session-key.js";
25
25
  import { logDebug } from "../utils/logger.js";
26
26
  export function createLlmInputHandler(deps) {
27
27
  const { enabled, logger } = deps;
28
28
  return (event, ctx) => {
29
29
  if (!ctx.sessionKey)
30
30
  return;
31
- if (event.runId && isGroupOrChannelSessionKey(ctx.sessionKey)) {
31
+ if (event.runId && needsSenderIsolation(ctx.sessionKey)) {
32
32
  const effectiveKey = resolveEffectiveSessionKey(ctx.sessionKey);
33
33
  if (effectiveKey !== ctx.sessionKey) {
34
34
  freezeRun(event.runId, effectiveKey);
@@ -16,7 +16,7 @@
16
16
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
17
17
  import { propagateTIPToTarget } from "../services/tip-propagation.js";
18
18
  import { logWarn } from "../utils/logger.js";
19
- import { resolveEffectiveSessionKeyForRun } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKeyForRun } from "../store/sender-session-store.js";
20
20
  export function createSessionsSendPropagationHandler(deps) {
21
21
  const { storeDir, identityService, configWorkloadName, getOidcConfigForRefresh, subagentTipPropagation, logger, } = deps;
22
22
  return async (event, ctx) => {
@@ -16,7 +16,7 @@
16
16
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
17
17
  import { propagateTIPToTarget } from "../services/tip-propagation.js";
18
18
  import { logWarn } from "../utils/logger.js";
19
- import { resolveEffectiveSessionKeyForRun } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKeyForRun } from "../store/sender-session-store.js";
20
20
  export function createSessionsSpawnPropagationHandler(deps) {
21
21
  const { storeDir, identityService, configWorkloadName, getOidcConfigForRefresh, subagentTipPropagation, logger, } = deps;
22
22
  return async (event, ctx) => {
@@ -21,7 +21,7 @@
21
21
  */
22
22
  import { deleteSession } from "../store/session-store.js";
23
23
  import { deleteTIPToken } from "../store/tip-store.js";
24
- import { clearFrozenRun } from "../store/group-sender-store.js";
24
+ import { clearFrozenRun } from "../store/sender-session-store.js";
25
25
  import { logDebug, logWarn } from "../utils/logger.js";
26
26
  export function createSubagentEndedCleanupHandler(deps) {
27
27
  const { storeDir, logger } = deps;
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-login.d.ts","sourceRoot":"","sources":["../../../src/routes/oidc-login.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAKvE,MAAM,MAAM,eAAe,GAAG;IAC5B,oGAAoG;IACpG,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kHAAkH;IAClH,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,oHAAoH;IACpH,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,gBAAgB,IAGhD,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CA4ExE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClD,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,+FAA+F;AAC/F,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAGxD,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CA6ExE"}
1
+ {"version":3,"file":"oidc-login.d.ts","sourceRoot":"","sources":["../../../src/routes/oidc-login.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AASvE,MAAM,MAAM,eAAe,GAAG;IAC5B,oGAAoG;IACpG,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kHAAkH;IAClH,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,oHAAoH;IACpH,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,gBAAgB,IAGhD,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CAsGxE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClD,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,+FAA+F;AAC/F,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAGxD,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CAuGxE"}
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { fetchOIDCDiscovery, exchangeCodeForTokens } from "../services/oidc-client.js";
16
+ import { fetchOIDCDiscovery, exchangeCodeForTokens, verifyIdToken, } from "../services/oidc-client.js";
17
17
  import { consumeState } from "../store/oidc-state-store.js";
18
18
  import { setSession } from "../store/session-store.js";
19
19
  export function createOIDCCallbackHandler(deps) {
@@ -56,10 +56,31 @@ export function createOIDCCallbackHandler(deps) {
56
56
  clientSecret: config.clientSecret,
57
57
  code,
58
58
  redirectUri: config.callbackUrl,
59
+ codeVerifier: entry.codeVerifier,
59
60
  });
60
- const userToken = tokens.id_token ?? tokens.access_token;
61
- const parsed = identityService.parseUserToken(userToken);
62
- const sub = parsed.sub ?? "unknown";
61
+ const idToken = tokens.id_token;
62
+ if (!idToken) {
63
+ res.statusCode = 400;
64
+ res.setHeader("Content-Type", "application/json");
65
+ res.end(JSON.stringify({ error: "Token response missing id_token (required for OIDC)" }));
66
+ return;
67
+ }
68
+ if (!discovery.jwks_uri || !discovery.issuer) {
69
+ res.statusCode = 500;
70
+ res.setHeader("Content-Type", "application/json");
71
+ res.end(JSON.stringify({
72
+ error: "OIDC discovery missing jwks_uri or issuer; cannot verify id_token",
73
+ }));
74
+ return;
75
+ }
76
+ const { sub } = await verifyIdToken({
77
+ idToken,
78
+ jwksUri: discovery.jwks_uri,
79
+ issuer: discovery.issuer,
80
+ audience: config.clientId,
81
+ nonce: entry.nonce,
82
+ });
83
+ const userToken = idToken;
63
84
  await setSession(storeDir, entry.sessionKey, {
64
85
  userToken,
65
86
  sub,
@@ -128,10 +149,31 @@ export function createOIDCCallbackHandlerLazy(deps) {
128
149
  clientSecret: config.clientSecret,
129
150
  code,
130
151
  redirectUri: config.callbackUrl,
152
+ codeVerifier: entry.codeVerifier,
153
+ });
154
+ const idToken = tokens.id_token;
155
+ if (!idToken) {
156
+ res.statusCode = 400;
157
+ res.setHeader("Content-Type", "application/json");
158
+ res.end(JSON.stringify({ error: "Token response missing id_token (required for OIDC)" }));
159
+ return;
160
+ }
161
+ if (!discovery.jwks_uri || !discovery.issuer) {
162
+ res.statusCode = 500;
163
+ res.setHeader("Content-Type", "application/json");
164
+ res.end(JSON.stringify({
165
+ error: "OIDC discovery missing jwks_uri or issuer; cannot verify id_token",
166
+ }));
167
+ return;
168
+ }
169
+ const { sub } = await verifyIdToken({
170
+ idToken,
171
+ jwksUri: discovery.jwks_uri,
172
+ issuer: discovery.issuer,
173
+ audience: config.clientId,
174
+ nonce: entry.nonce,
131
175
  });
132
- const userToken = tokens.id_token ?? tokens.access_token;
133
- const parsed = identityService.parseUserToken(userToken);
134
- const sub = parsed.sub ?? "unknown";
176
+ const userToken = idToken;
135
177
  await setSession(storeDir, entry.sessionKey, {
136
178
  userToken,
137
179
  sub,
@@ -24,8 +24,9 @@ export declare class IdentityService {
24
24
  sub?: string;
25
25
  }): Promise<TIPTokenEntry>;
26
26
  /**
27
- * Validate user token (basic JWT decode for sub; full validation would use UserPool JWKS).
28
- * For now we trust tokens that are stored via login flow.
27
+ * Lightweight expiry check for stored user tokens.
28
+ * Signature verification is performed at the trust boundary (OIDC callback and token refresh),
29
+ * so tokens stored in session are already verified. This method only checks format and expiry.
29
30
  */
30
31
  parseUserToken(userToken: string): {
31
32
  valid: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"identity-service.d.ts","sourceRoot":"","sources":["../../../src/services/identity-service.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,uBAAuB,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,qBAAqB;IAEpD,sBAAsB,CAAC,MAAM,EAAE;QACnC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,sFAAsF;QACtF,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,aAAa,CAAC;IA2B1B;;;OAGG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;CAiBpE"}
1
+ {"version":3,"file":"identity-service.d.ts","sourceRoot":"","sources":["../../../src/services/identity-service.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,uBAAuB,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,qBAAqB;IAEpD,sBAAsB,CAAC,MAAM,EAAE;QACnC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,sFAAsF;QACtF,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,aAAa,CAAC;IA2B1B;;;;OAIG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;CAiBpE"}
@@ -42,8 +42,9 @@ export class IdentityService {
42
42
  };
43
43
  }
44
44
  /**
45
- * Validate user token (basic JWT decode for sub; full validation would use UserPool JWKS).
46
- * For now we trust tokens that are stored via login flow.
45
+ * Lightweight expiry check for stored user tokens.
46
+ * Signature verification is performed at the trust boundary (OIDC callback and token refresh),
47
+ * so tokens stored in session are already verified. This method only checks format and expiry.
47
48
  */
48
49
  parseUserToken(userToken) {
49
50
  try {
@@ -1,11 +1,3 @@
1
- /**
2
- * OIDC client for UserPool login flow.
3
- * Fetches .well-known/openid-configuration from data plane, then:
4
- * - Build authorization URL for login
5
- * - Exchange code for tokens
6
- *
7
- * Reference: veadk auth/middleware/oauth2_auth.py
8
- */
9
1
  /** Default OIDC scope for login. Includes offline_access for refresh_token support. */
10
2
  export declare const DEFAULT_OIDC_SCOPE = "openid profile email offline_access";
11
3
  export type OIDCDiscovery = {
@@ -28,7 +20,14 @@ export declare function buildAuthorizationUrl(params: {
28
20
  responseType?: string;
29
21
  codeChallenge?: string;
30
22
  codeChallengeMethod?: string;
23
+ nonce?: string;
31
24
  }): string;
25
+ /** Generate PKCE code_verifier and code_challenge (S256). */
26
+ export declare function generatePKCE(): Promise<{
27
+ codeVerifier: string;
28
+ codeChallenge: string;
29
+ }>;
30
+ export declare function generateNonce(): Promise<string>;
32
31
  export declare function exchangeCodeForTokens(params: {
33
32
  tokenEndpoint: string;
34
33
  clientId: string;
@@ -43,6 +42,24 @@ export declare function exchangeCodeForTokens(params: {
43
42
  refresh_token?: string;
44
43
  id_token?: string;
45
44
  }>;
45
+ export type VerifyIdTokenParams = {
46
+ idToken: string;
47
+ jwksUri: string;
48
+ issuer: string;
49
+ audience: string;
50
+ /** Expected nonce (must match nonce claim in id_token when provided). */
51
+ nonce?: string;
52
+ };
53
+ export type VerifyIdTokenResult = {
54
+ sub: string;
55
+ };
56
+ /**
57
+ * Verify id_token using IdP's JWKS (public key).
58
+ * Validates signature, issuer, audience, expiry, and nonce per OIDC spec.
59
+ * JWKS instances are cached per jwks_uri to avoid redundant remote fetches.
60
+ * MUST be called before marking user as logged in.
61
+ */
62
+ export declare function verifyIdToken(params: VerifyIdTokenParams): Promise<VerifyIdTokenResult>;
46
63
  /** Refresh access/id token using refresh_token grant. */
47
64
  export declare function refreshAccessToken(params: {
48
65
  tokenEndpoint: string;
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-client.d.ts","sourceRoot":"","sources":["../../../src/services/oidc-client.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AAEH,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AAExE,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,GAAG,MAAM,CA0BT;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CA6CD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAwCD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD"}
1
+ {"version":3,"file":"oidc-client.d.ts","sourceRoot":"","sources":["../../../src/services/oidc-client.ts"],"names":[],"mappings":"AA4BA,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AAaxE,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA8BT;AAED,6DAA6D;AAC7D,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7F;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CA6CD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B7F;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAwCD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD"}
@@ -18,11 +18,22 @@
18
18
  * Fetches .well-known/openid-configuration from data plane, then:
19
19
  * - Build authorization URL for login
20
20
  * - Exchange code for tokens
21
+ * - Verify id_token using IdP JWKS before trusting identity
21
22
  *
22
23
  * Reference: veadk auth/middleware/oauth2_auth.py
23
24
  */
25
+ import { createRemoteJWKSet, jwtVerify } from "jose";
24
26
  /** Default OIDC scope for login. Includes offline_access for refresh_token support. */
25
27
  export const DEFAULT_OIDC_SCOPE = "openid profile email offline_access";
28
+ const jwksCache = new Map();
29
+ function getOrCreateJWKS(jwksUri) {
30
+ let jwks = jwksCache.get(jwksUri);
31
+ if (!jwks) {
32
+ jwks = createRemoteJWKSet(new URL(jwksUri));
33
+ jwksCache.set(jwksUri, jwks);
34
+ }
35
+ return jwks;
36
+ }
26
37
  export async function fetchOIDCDiscovery(discoveryUrl, timeoutMs = 10_000) {
27
38
  const controller = new AbortController();
28
39
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -46,7 +57,7 @@ export async function fetchOIDCDiscovery(discoveryUrl, timeoutMs = 10_000) {
46
57
  }
47
58
  }
48
59
  export function buildAuthorizationUrl(params) {
49
- const { authorizationEndpoint, clientId, redirectUri, scope = DEFAULT_OIDC_SCOPE, state, responseType = "code", codeChallenge, codeChallengeMethod, } = params;
60
+ const { authorizationEndpoint, clientId, redirectUri, scope = DEFAULT_OIDC_SCOPE, state, responseType = "code", codeChallenge, codeChallengeMethod, nonce, } = params;
50
61
  const search = new URLSearchParams({
51
62
  response_type: responseType,
52
63
  client_id: clientId,
@@ -58,9 +69,23 @@ export function buildAuthorizationUrl(params) {
58
69
  search.set("code_challenge", codeChallenge);
59
70
  search.set("code_challenge_method", codeChallengeMethod ?? "S256");
60
71
  }
72
+ if (nonce) {
73
+ search.set("nonce", nonce);
74
+ }
61
75
  const sep = authorizationEndpoint.includes("?") ? "&" : "?";
62
76
  return `${authorizationEndpoint}${sep}${search.toString()}`;
63
77
  }
78
+ /** Generate PKCE code_verifier and code_challenge (S256). */
79
+ export async function generatePKCE() {
80
+ const { randomBytes, createHash } = await import("node:crypto");
81
+ const codeVerifier = randomBytes(32).toString("base64url");
82
+ const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
83
+ return { codeVerifier, codeChallenge };
84
+ }
85
+ export async function generateNonce() {
86
+ const { randomBytes } = await import("node:crypto");
87
+ return randomBytes(16).toString("base64url");
88
+ }
64
89
  export async function exchangeCodeForTokens(params) {
65
90
  const { tokenEndpoint, clientId, clientSecret, code, redirectUri, codeVerifier } = params;
66
91
  const body = new URLSearchParams({
@@ -102,6 +127,35 @@ export async function exchangeCodeForTokens(params) {
102
127
  id_token: data.id_token,
103
128
  };
104
129
  }
130
+ /**
131
+ * Verify id_token using IdP's JWKS (public key).
132
+ * Validates signature, issuer, audience, expiry, and nonce per OIDC spec.
133
+ * JWKS instances are cached per jwks_uri to avoid redundant remote fetches.
134
+ * MUST be called before marking user as logged in.
135
+ */
136
+ export async function verifyIdToken(params) {
137
+ const { idToken, jwksUri, issuer, audience, nonce } = params;
138
+ if (!jwksUri) {
139
+ throw new Error("OIDC discovery missing jwks_uri; cannot verify id_token");
140
+ }
141
+ const JWKS = getOrCreateJWKS(jwksUri);
142
+ const { payload } = await jwtVerify(idToken, JWKS, {
143
+ issuer,
144
+ audience,
145
+ clockTolerance: 60,
146
+ });
147
+ const sub = payload.sub;
148
+ if (!sub || typeof sub !== "string") {
149
+ throw new Error("id_token missing sub claim");
150
+ }
151
+ if (nonce) {
152
+ const tokenNonce = payload.nonce;
153
+ if (tokenNonce !== nonce) {
154
+ throw new Error("id_token nonce mismatch (possible replay attack)");
155
+ }
156
+ }
157
+ return { sub };
158
+ }
105
159
  /** Refresh access/id token using refresh_token grant. */
106
160
  export async function refreshAccessToken(params) {
107
161
  const { tokenEndpoint, clientId, clientSecret, refreshToken } = params;
@@ -1 +1 @@
1
- {"version":3,"file":"session-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/session-refresh.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BxB"}
1
+ {"version":3,"file":"session-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/session-refresh.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsCxB"}
@@ -18,7 +18,7 @@
18
18
  * Used by before_agent_start when GetWorkloadAccessTokenForJWT fails with "token has expired".
19
19
  */
20
20
  import { getSession, setSession } from "../store/session-store.js";
21
- import { fetchOIDCDiscovery, refreshAccessToken } from "./oidc-client.js";
21
+ import { fetchOIDCDiscovery, refreshAccessToken, verifyIdToken } from "./oidc-client.js";
22
22
  /**
23
23
  * Refresh session userToken using refresh_token grant.
24
24
  * Updates session with new userToken (and rotated refresh_token if returned).
@@ -37,7 +37,16 @@ export async function refreshSessionUserToken(storeDir, sessionKey, getOidcConfi
37
37
  clientSecret: config.clientSecret,
38
38
  refreshToken: session.refreshToken,
39
39
  });
40
- const userToken = tokens.id_token ?? tokens.access_token;
40
+ const idToken = tokens.id_token;
41
+ if (idToken && discovery.jwks_uri && discovery.issuer) {
42
+ await verifyIdToken({
43
+ idToken,
44
+ jwksUri: discovery.jwks_uri,
45
+ issuer: discovery.issuer,
46
+ audience: config.clientId,
47
+ });
48
+ }
49
+ const userToken = idToken ?? tokens.access_token;
41
50
  const newRefreshToken = tokens.refresh_token ?? session.refreshToken;
42
51
  await setSession(storeDir, sessionKey, {
43
52
  ...session,
@@ -9,7 +9,14 @@ export type OIDCStateEntry = {
9
9
  createdAt: number;
10
10
  /** Delivery target for sending follow-up message; avoids parsing sessionKey. */
11
11
  deliveryTarget?: SessionKeyDeliveryTarget | null;
12
+ /** PKCE code_verifier for S256 challenge; sent in token exchange. */
13
+ codeVerifier?: string;
14
+ /** Nonce sent in authorization request; validated against id_token nonce claim. */
15
+ nonce?: string;
12
16
  };
13
- export declare function createState(_storeDir: string, sessionKey: string, redirectUri: string, state: string, deliveryTarget?: SessionKeyDeliveryTarget | null): Promise<void>;
17
+ export declare function createState(_storeDir: string, sessionKey: string, redirectUri: string, state: string, deliveryTarget?: SessionKeyDeliveryTarget | null, extra?: {
18
+ codeVerifier?: string;
19
+ nonce?: string;
20
+ }): Promise<void>;
14
21
  export declare function consumeState(_storeDir: string, state: string): Promise<OIDCStateEntry | null>;
15
22
  //# sourceMappingURL=oidc-state-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-state-store.d.ts","sourceRoot":"","sources":["../../../src/store/oidc-state-store.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE/E,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAClD,CAAC;AAYF,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,GAC/C,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC"}
1
+ {"version":3,"file":"oidc-state-store.d.ts","sourceRoot":"","sources":["../../../src/store/oidc-state-store.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE/E,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACjD,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAYF,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,EAChD,KAAK,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC"}
@@ -22,13 +22,15 @@ function pruneExpired() {
22
22
  states.delete(k);
23
23
  }
24
24
  }
25
- export async function createState(_storeDir, sessionKey, redirectUri, state, deliveryTarget) {
25
+ export async function createState(_storeDir, sessionKey, redirectUri, state, deliveryTarget, extra) {
26
26
  pruneExpired();
27
27
  states.set(state, {
28
28
  sessionKey,
29
29
  redirectUri,
30
30
  createdAt: Date.now(),
31
31
  deliveryTarget: deliveryTarget ?? undefined,
32
+ codeVerifier: extra?.codeVerifier,
33
+ nonce: extra?.nonce,
32
34
  });
33
35
  }
34
36
  export async function consumeState(_storeDir, state) {
@@ -10,16 +10,23 @@ export declare function setSender(sessionKey: string, info: SenderInfo): void;
10
10
  export declare function getSender(sessionKey: string): SenderInfo | undefined;
11
11
  export declare function clearSender(sessionKey: string): void;
12
12
  /**
13
- * For group sessions, append :user:<senderId> so each member gets isolated
14
- * TIP tokens, credentials and session state.
15
- * For non-group sessions the key is returned unchanged.
13
+ * For shared sessions (group/channel and default "main"), resolve to a
14
+ * user-scoped effective key so each user gets isolated state.
15
+ *
16
+ * For main shared sessions from a sendable channel, promote the key to
17
+ * per-channel-peer format (agent:{id}:{channel}:direct:{senderId}).
18
+ * This makes the key parseable by parseSessionKeyToDeliveryTarget,
19
+ * enabling message delivery after OIDC login and approval flows.
20
+ *
21
+ * For group sessions or main sessions without channel info, fall back to
22
+ * appending :user:<senderId>.
16
23
  */
17
24
  export declare function resolveEffectiveSessionKey(sessionKey: string): string;
18
25
  /**
19
- * Same as resolveEffectiveSessionKey but takes an explicit senderId
20
- * (used by commands where ctx.senderId is already available).
26
+ * Same as resolveEffectiveSessionKey but takes explicit senderId and channel
27
+ * (used by commands where ctx.senderId and ctx.channel are directly available).
21
28
  */
22
- export declare function buildEffectiveSessionKey(sessionKey: string, senderId?: string): string;
29
+ export declare function buildEffectiveSessionKey(sessionKey: string, senderId?: string, channel?: string): string;
23
30
  /**
24
31
  * Freeze the effective sessionKey for a runId.
25
32
  * Once frozen, all hooks in this run use the same user-scoped key
@@ -32,4 +39,4 @@ export declare function freezeRun(runId: string, effectiveKey: string): void;
32
39
  */
33
40
  export declare function resolveEffectiveSessionKeyForRun(sessionKey: string, runId?: string): string;
34
41
  export declare function clearFrozenRun(runId: string): void;
35
- //# sourceMappingURL=group-sender-store.d.ts.map
42
+ //# sourceMappingURL=sender-session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender-session-store.d.ts","sourceRoot":"","sources":["../../../src/store/sender-session-store.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAGpE;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAQpE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAEpD;AAkBD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CASrE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAOR;AASD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAInE;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ3F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAElD"}
@@ -14,11 +14,14 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  /**
17
- * Lightweight in-memory store that maps group sessionKey → latest sender info.
18
- * Written by the message_received handler, read by before_tool_call to inject
19
- * sender identity into tool params so group-chat users can be distinguished.
17
+ * Lightweight in-memory store that maps shared sessionKey → latest sender info.
18
+ * Covers both group/channel sessions and default "main" sessions (dmScope unset).
19
+ *
20
+ * For main sessions from sendable channels, the effective key is promoted to
21
+ * per-channel-peer format (agent:{id}:{channel}:direct:{senderId}), making it
22
+ * parseable for message delivery after OIDC login and approval flows.
20
23
  */
21
- import { isGroupOrChannelSessionKey } from "../utils/derive-session-key.js";
24
+ import { needsSenderIsolation, isMainSharedSessionKey, parseAgentIdFromSessionKey, isSendableChannel, } from "../utils/derive-session-key.js";
22
25
  const SESSION_TTL_MS = 2 * 60 * 60 * 1000;
23
26
  const store = new Map();
24
27
  export function setSender(sessionKey, info) {
@@ -39,25 +42,51 @@ export function clearSender(sessionKey) {
39
42
  store.delete(sessionKey);
40
43
  }
41
44
  /**
42
- * For group sessions, append :user:<senderId> so each member gets isolated
43
- * TIP tokens, credentials and session state.
44
- * For non-group sessions the key is returned unchanged.
45
+ * Build a per-channel-peer key from a main shared session when channel is sendable.
46
+ * Returns null if the key can't be promoted (not main, or channel not sendable).
47
+ */
48
+ function promoteMainToChannelPeerKey(sessionKey, channel, senderId) {
49
+ if (!isMainSharedSessionKey(sessionKey))
50
+ return null;
51
+ const ch = (channel ?? "").trim().toLowerCase();
52
+ if (!ch || !isSendableChannel(ch))
53
+ return null;
54
+ const agentId = parseAgentIdFromSessionKey(sessionKey) ?? "main";
55
+ return `agent:${agentId}:${ch}:direct:${senderId.toLowerCase()}`;
56
+ }
57
+ /**
58
+ * For shared sessions (group/channel and default "main"), resolve to a
59
+ * user-scoped effective key so each user gets isolated state.
60
+ *
61
+ * For main shared sessions from a sendable channel, promote the key to
62
+ * per-channel-peer format (agent:{id}:{channel}:direct:{senderId}).
63
+ * This makes the key parseable by parseSessionKeyToDeliveryTarget,
64
+ * enabling message delivery after OIDC login and approval flows.
65
+ *
66
+ * For group sessions or main sessions without channel info, fall back to
67
+ * appending :user:<senderId>.
45
68
  */
46
69
  export function resolveEffectiveSessionKey(sessionKey) {
47
- if (!isGroupOrChannelSessionKey(sessionKey))
70
+ if (!needsSenderIsolation(sessionKey))
48
71
  return sessionKey;
49
72
  const sender = getSender(sessionKey);
50
73
  if (!sender?.senderId)
51
74
  return sessionKey;
75
+ const promoted = promoteMainToChannelPeerKey(sessionKey, sender.channelId, sender.senderId);
76
+ if (promoted)
77
+ return promoted;
52
78
  return `${sessionKey}:user:${sender.senderId}`;
53
79
  }
54
80
  /**
55
- * Same as resolveEffectiveSessionKey but takes an explicit senderId
56
- * (used by commands where ctx.senderId is already available).
81
+ * Same as resolveEffectiveSessionKey but takes explicit senderId and channel
82
+ * (used by commands where ctx.senderId and ctx.channel are directly available).
57
83
  */
58
- export function buildEffectiveSessionKey(sessionKey, senderId) {
59
- if (!senderId || !isGroupOrChannelSessionKey(sessionKey))
84
+ export function buildEffectiveSessionKey(sessionKey, senderId, channel) {
85
+ if (!senderId || !needsSenderIsolation(sessionKey))
60
86
  return sessionKey;
87
+ const promoted = promoteMainToChannelPeerKey(sessionKey, channel, senderId);
88
+ if (promoted)
89
+ return promoted;
61
90
  return `${sessionKey}:user:${senderId}`;
62
91
  }
63
92
  // --------------- freeze-by-runId ---------------
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import * as toolApprovalStore from "../store/tool-approval-store.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  import { logDebug, logWarn } from "../utils/logger.js";
21
21
  export function createIdentityApproveTool(deps) {
22
22
  return (ctx) => ({
@@ -18,7 +18,7 @@ import { optionalStringEnum } from "openclaw/plugin-sdk";
18
18
  import { jsonResult } from "openclaw/plugin-sdk";
19
19
  import { runFetch } from "../actions/identity-actions.js";
20
20
  import { getCredential, resolveCredentialValue } from "../store/credential-store.js";
21
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
21
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
22
22
  const FETCH_FLOWS = ["oauth2-user", "oauth2-m2m", "apikey"];
23
23
  export function createIdentityFetchTool(deps) {
24
24
  return (ctx) => ({
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runListCredentials } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityListCredentialsTool(deps) {
21
21
  return (ctx) => ({
22
22
  name: "identity_list_credentials",
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runLogin } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityLoginTool(deps) {
21
21
  return (ctx) => ({
22
22
  name: "identity_login",
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runLogout } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityLogoutTool(deps) {
21
21
  return (ctx) => {
22
22
  const sessionKey = ctx.sessionKey ? resolveEffectiveSessionKey(ctx.sessionKey) : undefined;
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runSetBinding } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentitySetBindingTool(deps) {
21
21
  return (ctx) => ({
22
22
  name: "identity_set_binding",
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runStatus } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityStatusTool(deps) {
21
21
  return (ctx) => ({
22
22
  name: "identity_status",
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runUnsetBinding } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityUnsetBindingTool(deps) {
21
21
  return (ctx) => ({
22
22
  name: "identity_unset_binding",
@@ -16,7 +16,7 @@
16
16
  import { Type } from "@sinclair/typebox";
17
17
  import { jsonResult } from "openclaw/plugin-sdk";
18
18
  import { runStatus } from "../actions/identity-actions.js";
19
- import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
19
+ import { resolveEffectiveSessionKey } from "../store/sender-session-store.js";
20
20
  export function createIdentityWhoamiTool(deps) {
21
21
  return (ctx) => {
22
22
  const sessionKey = ctx.sessionKey ? resolveEffectiveSessionKey(ctx.sessionKey) : undefined;
@@ -49,12 +49,35 @@ export declare function resolveAgentId(params: ResolveAgentIdParams): string;
49
49
  */
50
50
  export declare function isSubagentSessionKey(sessionKey: string | undefined | null): boolean;
51
51
  /**
52
- * Check whether sessionKey represents a group/channel conversation.
53
- * Examples:
54
- * - agent:main:telegram:group:-1001
55
- * - agent:main:slack:channel:C123456
52
+ * Check whether sessionKey represents a group/channel conversation
53
+ * by parsing the key structure: agent:{agentId}:{channel}:{scope}:{peerId}...
54
+ * where scope is "group" or "channel".
55
+ *
56
+ * This is stricter than a naive `:group:` substring match — it only checks
57
+ * position [3] of the colon-delimited key, preventing false positives from
58
+ * user-scoped suffixes like `...:user:some_group_admin`.
56
59
  */
57
60
  export declare function isGroupOrChannelSessionKey(sessionKey: string | undefined | null): boolean;
61
+ /**
62
+ * Check whether sessionKey is the default "main" shared session (agent:{id}:main).
63
+ * When dmScope is unset, all DM users share this key — including:
64
+ * - Feishu/Telegram/etc. DMs (have senderId, will be isolated)
65
+ * - webchat/tui (typically no senderId; single-user, so no isolation needed)
66
+ */
67
+ export declare function isMainSharedSessionKey(sessionKey: string | undefined | null): boolean;
68
+ /**
69
+ * Whether the sessionKey may be shared by multiple users and thus requires
70
+ * per-sender isolation (appending :user:<senderId>).
71
+ * True for group/channel sessions AND default "main" sessions.
72
+ *
73
+ * Safety for webchat/tui: these channels typically don't provide senderId.
74
+ * When senderId is absent, the isolation gracefully degrades:
75
+ * - message_received handler skips (no senderId → early return)
76
+ * - resolveEffectiveSessionKey returns key unchanged (no stored sender)
77
+ * - buildEffectiveSessionKey returns key unchanged (senderId is undefined)
78
+ * So webchat/tui users keep using `agent:main:main` directly — correct for single-user contexts.
79
+ */
80
+ export declare function needsSenderIsolation(sessionKey: string | undefined | null): boolean;
58
81
  export type ResolveWorkloadNameParams = {
59
82
  sessionKey?: string;
60
83
  agentId?: string;
@@ -67,6 +90,12 @@ export type ResolveWorkloadNameParams = {
67
90
  * For main/cron/etc: use configWorkloadName ?? agentId ?? "openclaw-agent".
68
91
  */
69
92
  export declare function resolveWorkloadNameForSession(params: ResolveWorkloadNameParams): string;
93
+ /**
94
+ * Check if the from/to context indicates a group conversation.
95
+ * Reuses the same per-channel logic as extractGroupPeerId.
96
+ * Use this at message-receive time when raw context fields are available.
97
+ */
98
+ export declare function isGroupContext(channel: string, from?: string, to?: string): boolean;
70
99
  /**
71
100
  * Derive sessionKey from command context.
72
101
  * Matches OpenClaw routing buildAgentPeerSessionKey for common cases.
@@ -78,6 +107,7 @@ export type SessionKeyDeliveryTarget = {
78
107
  /** For feishu per-account sessions (agent:main:feishu:default:direct:ou_xxx). */
79
108
  accountId?: string;
80
109
  };
110
+ export declare function isSendableChannel(channel: string | undefined | null): boolean;
81
111
  /** Command context shape (subset of PluginCommandContext). */
82
112
  export type CommandContextForDelivery = {
83
113
  channel: string;
@@ -1 +1 @@
1
- {"version":3,"file":"derive-session-key.d.ts","sourceRoot":"","sources":["../../../src/utils/derive-session-key.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,EAAE,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAC3D,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAUF;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAE/D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAM/F;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CASnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAIzF;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CAiBvF;AAsGD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI,CAiC9E;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAaF,8DAA8D;AAC9D,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,yBAAyB,GAC7B,wBAAwB,GAAG,IAAI,CAmBjC;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GACpC,wBAAwB,GAAG,IAAI,CAyDjC"}
1
+ {"version":3,"file":"derive-session-key.d.ts","sourceRoot":"","sources":["../../../src/utils/derive-session-key.ts"],"names":[],"mappings":"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"}
@@ -65,16 +65,50 @@ export function isSubagentSessionKey(sessionKey) {
65
65
  return raw.includes(":subagent:");
66
66
  }
67
67
  /**
68
- * Check whether sessionKey represents a group/channel conversation.
69
- * Examples:
70
- * - agent:main:telegram:group:-1001
71
- * - agent:main:slack:channel:C123456
68
+ * Check whether sessionKey represents a group/channel conversation
69
+ * by parsing the key structure: agent:{agentId}:{channel}:{scope}:{peerId}...
70
+ * where scope is "group" or "channel".
71
+ *
72
+ * This is stricter than a naive `:group:` substring match — it only checks
73
+ * position [3] of the colon-delimited key, preventing false positives from
74
+ * user-scoped suffixes like `...:user:some_group_admin`.
72
75
  */
73
76
  export function isGroupOrChannelSessionKey(sessionKey) {
74
77
  const raw = (sessionKey ?? "").trim().toLowerCase();
75
78
  if (!raw)
76
79
  return false;
77
- return raw.includes(":group:") || raw.includes(":channel:");
80
+ const parts = raw.split(":");
81
+ if (parts.length < 5 || parts[0] !== "agent")
82
+ return false;
83
+ const scope = parts[3];
84
+ return scope === "group" || scope === "channel";
85
+ }
86
+ /**
87
+ * Check whether sessionKey is the default "main" shared session (agent:{id}:main).
88
+ * When dmScope is unset, all DM users share this key — including:
89
+ * - Feishu/Telegram/etc. DMs (have senderId, will be isolated)
90
+ * - webchat/tui (typically no senderId; single-user, so no isolation needed)
91
+ */
92
+ export function isMainSharedSessionKey(sessionKey) {
93
+ const raw = (sessionKey ?? "").trim().toLowerCase();
94
+ if (!raw)
95
+ return false;
96
+ return /^agent:[^:]+:main$/.test(raw);
97
+ }
98
+ /**
99
+ * Whether the sessionKey may be shared by multiple users and thus requires
100
+ * per-sender isolation (appending :user:<senderId>).
101
+ * True for group/channel sessions AND default "main" sessions.
102
+ *
103
+ * Safety for webchat/tui: these channels typically don't provide senderId.
104
+ * When senderId is absent, the isolation gracefully degrades:
105
+ * - message_received handler skips (no senderId → early return)
106
+ * - resolveEffectiveSessionKey returns key unchanged (no stored sender)
107
+ * - buildEffectiveSessionKey returns key unchanged (senderId is undefined)
108
+ * So webchat/tui users keep using `agent:main:main` directly — correct for single-user contexts.
109
+ */
110
+ export function needsSenderIsolation(sessionKey) {
111
+ return isGroupOrChannelSessionKey(sessionKey) || isMainSharedSessionKey(sessionKey);
78
112
  }
79
113
  /**
80
114
  * Resolve workload name for GetWorkloadAccessToken when roleTrn is not set.
@@ -180,6 +214,14 @@ function extractGroupPeerId(channel, from, to) {
180
214
  return pickFirst(pickByPrefix(fromRaw, `${ch}:group:`), pickByPrefix(fromRaw, `${ch}:channel:`), pickByPrefix(toRaw, `${ch}:group:`), pickByPrefix(toRaw, `${ch}:channel:`));
181
215
  }
182
216
  }
217
+ /**
218
+ * Check if the from/to context indicates a group conversation.
219
+ * Reuses the same per-channel logic as extractGroupPeerId.
220
+ * Use this at message-receive time when raw context fields are available.
221
+ */
222
+ export function isGroupContext(channel, from, to) {
223
+ return extractGroupPeerId(channel, from, to) !== null;
224
+ }
183
225
  /**
184
226
  * Derive sessionKey from command context.
185
227
  * Matches OpenClaw routing buildAgentPeerSessionKey for common cases.
@@ -223,6 +265,9 @@ const SENDABLE_CHANNELS = new Set([
223
265
  "line",
224
266
  "feishu",
225
267
  ]);
268
+ export function isSendableChannel(channel) {
269
+ return SENDABLE_CHANNELS.has((channel ?? "").trim().toLowerCase());
270
+ }
226
271
  /**
227
272
  * Derive delivery target directly from command context (channel, from, to).
228
273
  * Use this when sessionKey cannot be parsed reliably.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m1a0rz/agent-identity",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Agent Identity: UserPool (用户池) login, TIP token (工作负载令牌), credential hosting (凭据托管 OAuth2/API key), optional tool/skill permission control (CheckPermission) and risk approval. Integrates with Volcengine 智能体身份和权限管理平台.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,14 +12,15 @@
12
12
  "keywords": ["openclaw", "identity", "volcengine", "userpool", "credential", "TIP", "auth", "agent"],
13
13
  "license": "Apache-2.0",
14
14
  "dependencies": {
15
- "@sinclair/typebox": "0.34.48"
15
+ "@sinclair/typebox": "0.34.48",
16
+ "jose": "^5.9.6"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@types/node": "^22.0.0",
19
20
  "typescript": "^5.7.0"
20
21
  },
21
22
  "peerDependencies": {
22
- "openclaw": ">=2026.2.21"
23
+ "openclaw": ">=2026.3.8"
23
24
  },
24
25
  "peerDependenciesMeta": {
25
26
  "openclaw": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"group-sender-store.d.ts","sourceRoot":"","sources":["../../../src/store/group-sender-store.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAGpE;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAQpE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGtF;AASD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAInE;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ3F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAElD"}