@alfe.ai/openclaw-identity 0.0.4 → 0.0.6
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/dist/plugin.cjs +57 -8
- package/dist/plugin.d.cts +1 -0
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +57 -8
- package/package.json +2 -2
package/dist/plugin.cjs
CHANGED
|
@@ -73,6 +73,7 @@ const plugin = {
|
|
|
73
73
|
version: "0.0.1",
|
|
74
74
|
activate(api) {
|
|
75
75
|
const log = api.logger;
|
|
76
|
+
if (api.registrationMode && api.registrationMode !== "full") return;
|
|
76
77
|
log.info("Alfe Identity plugin activating...");
|
|
77
78
|
let client;
|
|
78
79
|
try {
|
|
@@ -85,6 +86,14 @@ const plugin = {
|
|
|
85
86
|
log.error(`Identity plugin: failed to resolve config — ${err instanceof Error ? err.message : String(err)}`);
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
89
|
+
let failureMode = "open";
|
|
90
|
+
client.getIntegrationConfig("alfe").then((alfeConfig) => {
|
|
91
|
+
const mode = alfeConfig.config.identity_failure_mode;
|
|
92
|
+
if (mode === "open" || mode === "closed" || mode === "permissive") failureMode = mode;
|
|
93
|
+
log.info(`Identity failure mode: ${failureMode}`);
|
|
94
|
+
}).catch(() => {
|
|
95
|
+
log.info(`Identity failure mode: ${failureMode} (default — config fetch failed)`);
|
|
96
|
+
});
|
|
88
97
|
const identityToolNames = /* @__PURE__ */ new Set();
|
|
89
98
|
const tools = [
|
|
90
99
|
defineTool({
|
|
@@ -255,6 +264,36 @@ const plugin = {
|
|
|
255
264
|
senderId: params.senderId,
|
|
256
265
|
toolName: params.toolName
|
|
257
266
|
})
|
|
267
|
+
}),
|
|
268
|
+
defineTool({
|
|
269
|
+
name: "request_identity_verification",
|
|
270
|
+
description: "Send a verification phrase to the claimed identity's phone (SMS) or email. The person must relay the phrase back to confirm they own that identity.",
|
|
271
|
+
parameters: _sinclair_typebox.Type.Object({
|
|
272
|
+
claimedIdentityId: _sinclair_typebox.Type.String({ description: "Identity being claimed" }),
|
|
273
|
+
requestingIdentityId: _sinclair_typebox.Type.String({ description: "Identity of the person making the claim" }),
|
|
274
|
+
requestingPlatform: _sinclair_typebox.Type.String({ description: "Platform the requester is on (discord, slack, chat, etc.)" }),
|
|
275
|
+
requestingPlatformId: _sinclair_typebox.Type.String({ description: "Requester's platform-specific user ID" }),
|
|
276
|
+
preferredChannel: _sinclair_typebox.Type.Optional(_sinclair_typebox.Type.String({ description: "'sms' or 'email'" }))
|
|
277
|
+
}),
|
|
278
|
+
handler: (params) => client.requestIdentityVerification({
|
|
279
|
+
claimedIdentityId: params.claimedIdentityId,
|
|
280
|
+
requestingIdentityId: params.requestingIdentityId,
|
|
281
|
+
requestingPlatform: params.requestingPlatform,
|
|
282
|
+
requestingPlatformId: params.requestingPlatformId,
|
|
283
|
+
preferredChannel: params.preferredChannel
|
|
284
|
+
})
|
|
285
|
+
}),
|
|
286
|
+
defineTool({
|
|
287
|
+
name: "confirm_identity_verification",
|
|
288
|
+
description: "Confirm a verification by providing the three-word phrase. On success, the requesting identity is merged into the claimed identity.",
|
|
289
|
+
parameters: _sinclair_typebox.Type.Object({
|
|
290
|
+
verificationId: _sinclair_typebox.Type.String({ description: "Verification ID returned from request_identity_verification" }),
|
|
291
|
+
phrase: _sinclair_typebox.Type.String({ description: "Three-word phrase the person received via SMS or email" })
|
|
292
|
+
}),
|
|
293
|
+
handler: (params) => client.confirmIdentityVerification({
|
|
294
|
+
verificationId: params.verificationId,
|
|
295
|
+
phrase: params.phrase
|
|
296
|
+
})
|
|
258
297
|
})
|
|
259
298
|
];
|
|
260
299
|
for (const tool of tools) {
|
|
@@ -296,6 +335,10 @@ const plugin = {
|
|
|
296
335
|
log.info(`Identity resolved: ${senderId} → ${resolveResult.identityId ?? "unknown"} (${resolveResult.status})`);
|
|
297
336
|
} catch (e) {
|
|
298
337
|
log.error(`Identity resolution failed for ${senderId}: ${e.message}`);
|
|
338
|
+
if (failureMode === "closed") return {
|
|
339
|
+
block: true,
|
|
340
|
+
blockReason: "Identity: identity service unavailable — access denied (closed mode)"
|
|
341
|
+
};
|
|
299
342
|
}
|
|
300
343
|
}, { priority: 100 });
|
|
301
344
|
api.on("before_tool_call", async (...args) => {
|
|
@@ -305,14 +348,20 @@ const plugin = {
|
|
|
305
348
|
const sessionKey = ctx.sessionKey;
|
|
306
349
|
if (!sessionKey) return;
|
|
307
350
|
const perms = getCached(sessionKey);
|
|
308
|
-
if (!perms)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
351
|
+
if (!perms) {
|
|
352
|
+
if (failureMode === "permissive") return;
|
|
353
|
+
return {
|
|
354
|
+
block: true,
|
|
355
|
+
blockReason: "Identity: no identity context established — tool access denied"
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (!perms.identified) {
|
|
359
|
+
if (failureMode === "permissive") return;
|
|
360
|
+
return {
|
|
361
|
+
block: true,
|
|
362
|
+
blockReason: "Identity: unknown sender identity — tool access denied"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
316
365
|
if (perms.deniedTools.includes("*") || perms.deniedTools.includes(event.toolName)) return {
|
|
317
366
|
block: true,
|
|
318
367
|
blockReason: `Identity: tool '${event.toolName}' is denied for your role`
|
package/dist/plugin.d.cts
CHANGED
|
@@ -23,6 +23,7 @@ interface ToolDef {
|
|
|
23
23
|
}
|
|
24
24
|
interface PluginApi {
|
|
25
25
|
logger: PluginLogger;
|
|
26
|
+
registrationMode?: "full" | "setup-only" | "setup-runtime" | "cli-metadata";
|
|
26
27
|
registerTool: (tool: ToolDef) => void;
|
|
27
28
|
on: (event: string, handler: (...args: unknown[]) => Promise<unknown>, options?: {
|
|
28
29
|
priority?: number;
|
package/dist/plugin.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ interface ToolDef {
|
|
|
23
23
|
}
|
|
24
24
|
interface PluginApi {
|
|
25
25
|
logger: PluginLogger;
|
|
26
|
+
registrationMode?: "full" | "setup-only" | "setup-runtime" | "cli-metadata";
|
|
26
27
|
registerTool: (tool: ToolDef) => void;
|
|
27
28
|
on: (event: string, handler: (...args: unknown[]) => Promise<unknown>, options?: {
|
|
28
29
|
priority?: number;
|
package/dist/plugin.js
CHANGED
|
@@ -73,6 +73,7 @@ const plugin = {
|
|
|
73
73
|
version: "0.0.1",
|
|
74
74
|
activate(api) {
|
|
75
75
|
const log = api.logger;
|
|
76
|
+
if (api.registrationMode && api.registrationMode !== "full") return;
|
|
76
77
|
log.info("Alfe Identity plugin activating...");
|
|
77
78
|
let client;
|
|
78
79
|
try {
|
|
@@ -85,6 +86,14 @@ const plugin = {
|
|
|
85
86
|
log.error(`Identity plugin: failed to resolve config — ${err instanceof Error ? err.message : String(err)}`);
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
89
|
+
let failureMode = "open";
|
|
90
|
+
client.getIntegrationConfig("alfe").then((alfeConfig) => {
|
|
91
|
+
const mode = alfeConfig.config.identity_failure_mode;
|
|
92
|
+
if (mode === "open" || mode === "closed" || mode === "permissive") failureMode = mode;
|
|
93
|
+
log.info(`Identity failure mode: ${failureMode}`);
|
|
94
|
+
}).catch(() => {
|
|
95
|
+
log.info(`Identity failure mode: ${failureMode} (default — config fetch failed)`);
|
|
96
|
+
});
|
|
88
97
|
const identityToolNames = /* @__PURE__ */ new Set();
|
|
89
98
|
const tools = [
|
|
90
99
|
defineTool({
|
|
@@ -255,6 +264,36 @@ const plugin = {
|
|
|
255
264
|
senderId: params.senderId,
|
|
256
265
|
toolName: params.toolName
|
|
257
266
|
})
|
|
267
|
+
}),
|
|
268
|
+
defineTool({
|
|
269
|
+
name: "request_identity_verification",
|
|
270
|
+
description: "Send a verification phrase to the claimed identity's phone (SMS) or email. The person must relay the phrase back to confirm they own that identity.",
|
|
271
|
+
parameters: Type.Object({
|
|
272
|
+
claimedIdentityId: Type.String({ description: "Identity being claimed" }),
|
|
273
|
+
requestingIdentityId: Type.String({ description: "Identity of the person making the claim" }),
|
|
274
|
+
requestingPlatform: Type.String({ description: "Platform the requester is on (discord, slack, chat, etc.)" }),
|
|
275
|
+
requestingPlatformId: Type.String({ description: "Requester's platform-specific user ID" }),
|
|
276
|
+
preferredChannel: Type.Optional(Type.String({ description: "'sms' or 'email'" }))
|
|
277
|
+
}),
|
|
278
|
+
handler: (params) => client.requestIdentityVerification({
|
|
279
|
+
claimedIdentityId: params.claimedIdentityId,
|
|
280
|
+
requestingIdentityId: params.requestingIdentityId,
|
|
281
|
+
requestingPlatform: params.requestingPlatform,
|
|
282
|
+
requestingPlatformId: params.requestingPlatformId,
|
|
283
|
+
preferredChannel: params.preferredChannel
|
|
284
|
+
})
|
|
285
|
+
}),
|
|
286
|
+
defineTool({
|
|
287
|
+
name: "confirm_identity_verification",
|
|
288
|
+
description: "Confirm a verification by providing the three-word phrase. On success, the requesting identity is merged into the claimed identity.",
|
|
289
|
+
parameters: Type.Object({
|
|
290
|
+
verificationId: Type.String({ description: "Verification ID returned from request_identity_verification" }),
|
|
291
|
+
phrase: Type.String({ description: "Three-word phrase the person received via SMS or email" })
|
|
292
|
+
}),
|
|
293
|
+
handler: (params) => client.confirmIdentityVerification({
|
|
294
|
+
verificationId: params.verificationId,
|
|
295
|
+
phrase: params.phrase
|
|
296
|
+
})
|
|
258
297
|
})
|
|
259
298
|
];
|
|
260
299
|
for (const tool of tools) {
|
|
@@ -296,6 +335,10 @@ const plugin = {
|
|
|
296
335
|
log.info(`Identity resolved: ${senderId} → ${resolveResult.identityId ?? "unknown"} (${resolveResult.status})`);
|
|
297
336
|
} catch (e) {
|
|
298
337
|
log.error(`Identity resolution failed for ${senderId}: ${e.message}`);
|
|
338
|
+
if (failureMode === "closed") return {
|
|
339
|
+
block: true,
|
|
340
|
+
blockReason: "Identity: identity service unavailable — access denied (closed mode)"
|
|
341
|
+
};
|
|
299
342
|
}
|
|
300
343
|
}, { priority: 100 });
|
|
301
344
|
api.on("before_tool_call", async (...args) => {
|
|
@@ -305,14 +348,20 @@ const plugin = {
|
|
|
305
348
|
const sessionKey = ctx.sessionKey;
|
|
306
349
|
if (!sessionKey) return;
|
|
307
350
|
const perms = getCached(sessionKey);
|
|
308
|
-
if (!perms)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
351
|
+
if (!perms) {
|
|
352
|
+
if (failureMode === "permissive") return;
|
|
353
|
+
return {
|
|
354
|
+
block: true,
|
|
355
|
+
blockReason: "Identity: no identity context established — tool access denied"
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (!perms.identified) {
|
|
359
|
+
if (failureMode === "permissive") return;
|
|
360
|
+
return {
|
|
361
|
+
block: true,
|
|
362
|
+
blockReason: "Identity: unknown sender identity — tool access denied"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
316
365
|
if (perms.deniedTools.includes("*") || perms.deniedTools.includes(event.toolName)) return {
|
|
317
366
|
block: true,
|
|
318
367
|
blockReason: `Identity: tool '${event.toolName}' is denied for your role`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-identity",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "OpenClaw identity plugin — identity resolution, access gating, permission enforcement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@sinclair/typebox": "^0.34.48",
|
|
31
|
-
"@alfe.ai/agent-api-client": "0.0.
|
|
31
|
+
"@alfe.ai/agent-api-client": "0.0.10",
|
|
32
32
|
"@alfe.ai/config": "0.0.8"
|
|
33
33
|
},
|
|
34
34
|
"license": "UNLICENSED",
|