meshsig 0.5.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/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/crypto.d.ts +43 -0
- package/dist/crypto.js +108 -0
- package/dist/crypto.js.map +1 -0
- package/dist/dashboard.html +635 -0
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +107 -0
- package/dist/demo.js.map +1 -0
- package/dist/discovery.d.ts +24 -0
- package/dist/discovery.js +119 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +459 -0
- package/dist/main.js.map +1 -0
- package/dist/peers.d.ts +35 -0
- package/dist/peers.js +227 -0
- package/dist/peers.js.map +1 -0
- package/dist/registry.d.ts +85 -0
- package/dist/registry.js +311 -0
- package/dist/registry.js.map +1 -0
- package/dist/server.d.ts +27 -0
- package/dist/server.js +433 -0
- package/dist/server.js.map +1 -0
- package/dist/terminal.d.ts +17 -0
- package/dist/terminal.js +175 -0
- package/dist/terminal.js.map +1 -0
- package/package.json +51 -0
- package/scripts/install.sh +271 -0
- package/scripts/invoke-mesh.sh +190 -0
- package/scripts/register-agent.sh +89 -0
- package/scripts/uninstall.sh +25 -0
- package/scripts/unregister-agent.sh +23 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# MeshSig Invoke — Secure agent-to-agent delegation
|
|
4
|
+
# Replaces invoke.sh with cryptographically signed communication.
|
|
5
|
+
# Every delegation is signed with Ed25519 and logged to MeshSig.
|
|
6
|
+
# ==============================================================================
|
|
7
|
+
|
|
8
|
+
TARGET="$1"
|
|
9
|
+
MESSAGE="$2"
|
|
10
|
+
CONTEXT="${3:-}"
|
|
11
|
+
|
|
12
|
+
if [ -z "$TARGET" ] || [ -z "$MESSAGE" ]; then
|
|
13
|
+
echo '{"error":"Usage: invoke-mesh.sh <client_name> <message> [context]"}'
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
MESH_URL="${MESHSIG_URL:-http://127.0.0.1:4888}"
|
|
18
|
+
GATEWAY_URL="${GATEWAY_URL:-http://127.0.0.1:3001}"
|
|
19
|
+
GATEWAY_SECRET="${GATEWAY_SECRET:-xrunly-secret-change-me}"
|
|
20
|
+
|
|
21
|
+
# Agent identity file (created on first run by setup)
|
|
22
|
+
IDENTITY_DIR="/opt/meshsig/identities"
|
|
23
|
+
CALLER_NAME="${OPENCLAW_AGENT_NAME:-$(readlink -f "$SCRIPT_DIR" | sed "s|.*clients/||" | cut -d/ -f1)}"
|
|
24
|
+
CALLER_IDENTITY="$IDENTITY_DIR/$CALLER_NAME.json"
|
|
25
|
+
TARGET_IDENTITY="$IDENTITY_DIR/$TARGET.json"
|
|
26
|
+
|
|
27
|
+
# ---- Ensure identities exist ------------------------------------------------
|
|
28
|
+
|
|
29
|
+
ensure_identity() {
|
|
30
|
+
local agent_name="$1"
|
|
31
|
+
local identity_file="$IDENTITY_DIR/$agent_name.json"
|
|
32
|
+
|
|
33
|
+
if [ ! -f "$identity_file" ]; then
|
|
34
|
+
# Register with MeshSig and save identity
|
|
35
|
+
local result=$(curl -s -X POST "$MESH_URL/agents/register" \
|
|
36
|
+
-H "Content-Type: application/json" \
|
|
37
|
+
-d "{\"name\":\"$agent_name\",\"capabilities\":[]}")
|
|
38
|
+
|
|
39
|
+
echo "$result" | python3 -c "
|
|
40
|
+
import sys, json, os
|
|
41
|
+
data = json.load(sys.stdin)
|
|
42
|
+
identity = data.get('identity', {})
|
|
43
|
+
record = data.get('record', {})
|
|
44
|
+
out = {
|
|
45
|
+
'did': identity.get('did',''),
|
|
46
|
+
'privateKey': identity.get('privateKey',''),
|
|
47
|
+
'publicKey': identity.get('publicKey',''),
|
|
48
|
+
'displayName': record.get('displayName', '$agent_name')
|
|
49
|
+
}
|
|
50
|
+
os.makedirs('$IDENTITY_DIR', exist_ok=True)
|
|
51
|
+
with open('$identity_file', 'w') as f:
|
|
52
|
+
json.dump(out, f, indent=2)
|
|
53
|
+
print(json.dumps({'registered': out['did']}))" 2>/dev/null
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
mkdir -p "$IDENTITY_DIR"
|
|
58
|
+
ensure_identity "$CALLER_NAME"
|
|
59
|
+
ensure_identity "$TARGET"
|
|
60
|
+
|
|
61
|
+
# ---- Read identities --------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
CALLER_DID=$(python3 -c "import json; print(json.load(open('$CALLER_IDENTITY'))['did'])" 2>/dev/null)
|
|
64
|
+
CALLER_KEY=$(python3 -c "import json; print(json.load(open('$CALLER_IDENTITY'))['privateKey'])" 2>/dev/null)
|
|
65
|
+
TARGET_DID=$(python3 -c "import json; print(json.load(open('$TARGET_IDENTITY'))['did'])" 2>/dev/null)
|
|
66
|
+
|
|
67
|
+
if [ -z "$CALLER_DID" ] || [ -z "$TARGET_DID" ]; then
|
|
68
|
+
echo '{"error":"Failed to load agent identities. Check MeshSig is running."}'
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ---- Ensure connection exists -----------------------------------------------
|
|
73
|
+
|
|
74
|
+
# Check if connection exists, create if not
|
|
75
|
+
CONNECTION=$(curl -s "$MESH_URL/connections?did=$CALLER_DID" | python3 -c "
|
|
76
|
+
import sys, json
|
|
77
|
+
data = json.load(sys.stdin)
|
|
78
|
+
conns = data.get('connections', [])
|
|
79
|
+
target = '$TARGET_DID'
|
|
80
|
+
for c in conns:
|
|
81
|
+
if c['agentADid'] == target or c['agentBDid'] == target:
|
|
82
|
+
print(c['channelId'])
|
|
83
|
+
break
|
|
84
|
+
" 2>/dev/null)
|
|
85
|
+
|
|
86
|
+
if [ -z "$CONNECTION" ]; then
|
|
87
|
+
# Perform handshake
|
|
88
|
+
CALLER_PKEY=$(python3 -c "import json; print(json.load(open('$CALLER_IDENTITY'))['privateKey'])" 2>/dev/null)
|
|
89
|
+
TARGET_PKEY=$(python3 -c "import json; print(json.load(open('$TARGET_IDENTITY'))['privateKey'])" 2>/dev/null)
|
|
90
|
+
|
|
91
|
+
curl -s -X POST "$MESH_URL/handshake" \
|
|
92
|
+
-H "Content-Type: application/json" \
|
|
93
|
+
-d "{\"fromDid\":\"$CALLER_DID\",\"toDid\":\"$TARGET_DID\",\"privateKeyA\":\"$CALLER_PKEY\",\"privateKeyB\":\"$TARGET_PKEY\",\"permissions\":[\"send:request\",\"execute:task\"]}" > /dev/null 2>&1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ---- Sign and send message via MeshSig ------------------------------------
|
|
97
|
+
|
|
98
|
+
# 1. Sign the message through MeshSig
|
|
99
|
+
FULL_MESSAGE="$MESSAGE"
|
|
100
|
+
if [ -n "$CONTEXT" ]; then
|
|
101
|
+
FULL_MESSAGE="$MESSAGE | Context: $CONTEXT"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
SIGN_RESULT=$(curl -s -X POST "$MESH_URL/messages/send" \
|
|
105
|
+
-H "Content-Type: application/json" \
|
|
106
|
+
-d "{
|
|
107
|
+
\"fromDid\": \"$CALLER_DID\",
|
|
108
|
+
\"toDid\": \"$TARGET_DID\",
|
|
109
|
+
\"message\": $(python3 -c "import json; print(json.dumps('$FULL_MESSAGE'))"),
|
|
110
|
+
\"privateKey\": \"$CALLER_KEY\"
|
|
111
|
+
}")
|
|
112
|
+
|
|
113
|
+
VERIFIED=$(echo "$SIGN_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('verified', False))" 2>/dev/null)
|
|
114
|
+
|
|
115
|
+
if [ "$VERIFIED" != "True" ]; then
|
|
116
|
+
echo "{\"error\":\"MeshSig signature verification failed\",\"details\":$SIGN_RESULT}"
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# 2. Forward to actual agent via agent-gateway — WITH verified identity context
|
|
121
|
+
CALLER_DISPLAY=$(python3 -c "import json; print(json.load(open('$CALLER_IDENTITY'))['displayName'])" 2>/dev/null)
|
|
122
|
+
CALLER_CAPS=$(curl -s "$MESH_URL/agents/$CALLER_DID" | python3 -c "
|
|
123
|
+
import sys,json
|
|
124
|
+
try:
|
|
125
|
+
a = json.load(sys.stdin).get('agent',{})
|
|
126
|
+
caps = ', '.join([c['type'] for c in a.get('capabilities',[])])
|
|
127
|
+
trust = a.get('trustScore', 0)
|
|
128
|
+
print(f'{caps} (trust: {trust*100:.0f}%)')
|
|
129
|
+
except:
|
|
130
|
+
print('')
|
|
131
|
+
" 2>/dev/null)
|
|
132
|
+
|
|
133
|
+
# Build enriched message with identity
|
|
134
|
+
ENRICHED_MESSAGE=$(python3 -c "
|
|
135
|
+
import json
|
|
136
|
+
caller = '$CALLER_DISPLAY'
|
|
137
|
+
caller_did = '$CALLER_DID'
|
|
138
|
+
caps = '$CALLER_CAPS'
|
|
139
|
+
msg = '''$MESSAGE'''
|
|
140
|
+
ctx = '''${CONTEXT:-}'''
|
|
141
|
+
|
|
142
|
+
parts = []
|
|
143
|
+
parts.append(f'[MeshSig Verified Message]')
|
|
144
|
+
parts.append(f'From: {caller} ({caller_did[:30]}...)')
|
|
145
|
+
if caps:
|
|
146
|
+
parts.append(f'Role: {caps}')
|
|
147
|
+
parts.append(f'Signature: Ed25519 verified ✓')
|
|
148
|
+
parts.append(f'')
|
|
149
|
+
parts.append(f'Task: {msg}')
|
|
150
|
+
if ctx:
|
|
151
|
+
parts.append(f'Context: {ctx}')
|
|
152
|
+
|
|
153
|
+
print(json.dumps('\n'.join(parts)))
|
|
154
|
+
")
|
|
155
|
+
|
|
156
|
+
RESPONSE=$(curl -s --max-time 120 -X POST "$GATEWAY_URL/invoke-agent" \
|
|
157
|
+
-H "Content-Type: application/json" \
|
|
158
|
+
-H "x-api-secret: $GATEWAY_SECRET" \
|
|
159
|
+
-d "{
|
|
160
|
+
\"target_client_name\": \"$TARGET\",
|
|
161
|
+
\"message\": $ENRICHED_MESSAGE,
|
|
162
|
+
\"context\": $(python3 -c "import json; print(json.dumps('${CONTEXT:-}'))")
|
|
163
|
+
}")
|
|
164
|
+
|
|
165
|
+
# 3. Log the response through MeshSig (signed by target)
|
|
166
|
+
TARGET_KEY=$(python3 -c "import json; print(json.load(open('$TARGET_IDENTITY'))['privateKey'])" 2>/dev/null)
|
|
167
|
+
|
|
168
|
+
RESPONSE_PREVIEW=$(echo "$RESPONSE" | python3 -c "
|
|
169
|
+
import sys, json
|
|
170
|
+
try:
|
|
171
|
+
data = json.load(sys.stdin)
|
|
172
|
+
text = data.get('response', data.get('message', str(data)))[:200]
|
|
173
|
+
print(text)
|
|
174
|
+
except:
|
|
175
|
+
print(sys.stdin.read()[:200])
|
|
176
|
+
" 2>/dev/null)
|
|
177
|
+
|
|
178
|
+
if [ -n "$RESPONSE_PREVIEW" ]; then
|
|
179
|
+
curl -s -X POST "$MESH_URL/messages/send" \
|
|
180
|
+
-H "Content-Type: application/json" \
|
|
181
|
+
-d "{
|
|
182
|
+
\"fromDid\": \"$TARGET_DID\",
|
|
183
|
+
\"toDid\": \"$CALLER_DID\",
|
|
184
|
+
\"message\": $(python3 -c "import json; print(json.dumps('$RESPONSE_PREVIEW'))"),
|
|
185
|
+
\"privateKey\": \"$TARGET_KEY\"
|
|
186
|
+
}" > /dev/null 2>&1
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# 4. Return the response (same format as original invoke.sh)
|
|
190
|
+
echo "$RESPONSE"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# MeshSig — Auto-register a new agent
|
|
4
|
+
#
|
|
5
|
+
# Called automatically when xrunly-api provisions a new agent.
|
|
6
|
+
# Usage: bash register-agent.sh <client_name>
|
|
7
|
+
# Example: bash register-agent.sh agent-mari---atendente-de--17734059
|
|
8
|
+
# ==============================================================================
|
|
9
|
+
|
|
10
|
+
CLIENT_NAME="$1"
|
|
11
|
+
if [ -z "$CLIENT_NAME" ]; then
|
|
12
|
+
echo '{"error":"client_name required"}'
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
MESH_URL="${MESHSIG_URL:-http://127.0.0.1:4888}"
|
|
17
|
+
IDENTITY_DIR="/opt/meshsig/identities"
|
|
18
|
+
identity_file="$IDENTITY_DIR/$CLIENT_NAME.json"
|
|
19
|
+
|
|
20
|
+
# Check MeshSig is running
|
|
21
|
+
if ! curl -s "$MESH_URL/health" > /dev/null 2>&1; then
|
|
22
|
+
echo '{"error":"meshsig not running"}'
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Already registered?
|
|
27
|
+
if [ -f "$identity_file" ]; then
|
|
28
|
+
did=$(python3 -c "import json; print(json.load(open('$identity_file'))['did'])" 2>/dev/null)
|
|
29
|
+
echo "{\"already_registered\":true,\"did\":\"$did\"}"
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Detect capabilities
|
|
34
|
+
case "$CLIENT_NAME" in
|
|
35
|
+
*gestor*|*gerente*|*manager*|*coo*|*ceo*)
|
|
36
|
+
caps='[{"type":"management","confidence":0.95},{"type":"delegation","confidence":0.9}]' ;;
|
|
37
|
+
*atendente*|*suporte*|*support*)
|
|
38
|
+
caps='[{"type":"customer-support","confidence":0.92}]' ;;
|
|
39
|
+
*sdr*|*vendas*|*sales*)
|
|
40
|
+
caps='[{"type":"sales","confidence":0.9},{"type":"sdr","confidence":0.88}]' ;;
|
|
41
|
+
*copy*|*redator*|*writer*|*content*)
|
|
42
|
+
caps='[{"type":"copywriting","confidence":0.93}]' ;;
|
|
43
|
+
*social*|*marketing*|*instagram*)
|
|
44
|
+
caps='[{"type":"social-media","confidence":0.91}]' ;;
|
|
45
|
+
*analista*|*analytics*|*dados*|*data*)
|
|
46
|
+
caps='[{"type":"analytics","confidence":0.87}]' ;;
|
|
47
|
+
*)
|
|
48
|
+
caps='[{"type":"general","confidence":0.8}]' ;;
|
|
49
|
+
esac
|
|
50
|
+
|
|
51
|
+
# Extract display name
|
|
52
|
+
display_name=$(echo "$CLIENT_NAME" | sed 's/^agent-//' | cut -d'-' -f1 | sed 's/./\U&/')
|
|
53
|
+
|
|
54
|
+
# Register
|
|
55
|
+
mkdir -p "$IDENTITY_DIR"
|
|
56
|
+
result=$(curl -s -X POST "$MESH_URL/agents/register" \
|
|
57
|
+
-H "Content-Type: application/json" \
|
|
58
|
+
-d "{\"name\":\"$display_name\",\"capabilities\":$caps}")
|
|
59
|
+
|
|
60
|
+
# Save identity file
|
|
61
|
+
echo "$result" | python3 -c "
|
|
62
|
+
import sys, json
|
|
63
|
+
data = json.load(sys.stdin)
|
|
64
|
+
identity = data.get('identity', {})
|
|
65
|
+
record = data.get('record', {})
|
|
66
|
+
out = {
|
|
67
|
+
'did': identity.get('did',''),
|
|
68
|
+
'privateKey': identity.get('privateKey',''),
|
|
69
|
+
'publicKey': identity.get('publicKey',''),
|
|
70
|
+
'displayName': record.get('displayName', ''),
|
|
71
|
+
'clientName': '$CLIENT_NAME'
|
|
72
|
+
}
|
|
73
|
+
with open('$identity_file', 'w') as f:
|
|
74
|
+
json.dump(out, f, indent=2)
|
|
75
|
+
print(json.dumps({'registered':True,'did':out['did'],'name':out['displayName']}))
|
|
76
|
+
" 2>/dev/null
|
|
77
|
+
|
|
78
|
+
# Auto-connect to managers
|
|
79
|
+
for mgr_file in "$IDENTITY_DIR"/agent-*gestor*.json "$IDENTITY_DIR"/agent-*gerente*.json; do
|
|
80
|
+
[ -f "$mgr_file" ] || continue
|
|
81
|
+
mgr_did=$(python3 -c "import json; print(json.load(open('$mgr_file'))['did'])" 2>/dev/null)
|
|
82
|
+
mgr_key=$(python3 -c "import json; print(json.load(open('$mgr_file'))['privateKey'])" 2>/dev/null)
|
|
83
|
+
new_did=$(python3 -c "import json; print(json.load(open('$identity_file'))['did'])" 2>/dev/null)
|
|
84
|
+
new_key=$(python3 -c "import json; print(json.load(open('$identity_file'))['privateKey'])" 2>/dev/null)
|
|
85
|
+
|
|
86
|
+
curl -s -X POST "$MESH_URL/handshake" \
|
|
87
|
+
-H "Content-Type: application/json" \
|
|
88
|
+
-d "{\"fromDid\":\"$mgr_did\",\"toDid\":\"$new_did\",\"privateKeyA\":\"$mgr_key\",\"privateKeyB\":\"$new_key\"}" > /dev/null 2>&1
|
|
89
|
+
done
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# MeshSig Uninstall — Restores original invoke.sh
|
|
4
|
+
# ==============================================================================
|
|
5
|
+
|
|
6
|
+
CLIENT_DIR="/root/clients"
|
|
7
|
+
|
|
8
|
+
echo ""
|
|
9
|
+
echo " Restoring original invoke.sh files..."
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
for d in "$CLIENT_DIR"/agent-*/; do
|
|
13
|
+
agent_name=$(basename "$d")
|
|
14
|
+
skill_dir="$d/.openclaw/workspace/skills/invoke-team"
|
|
15
|
+
backup="$skill_dir/invoke.sh.original"
|
|
16
|
+
|
|
17
|
+
if [ -f "$backup" ]; then
|
|
18
|
+
cp "$backup" "$skill_dir/invoke.sh"
|
|
19
|
+
echo " ✓ $agent_name — restored original invoke.sh"
|
|
20
|
+
fi
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
echo ""
|
|
24
|
+
echo " Done. MeshSig signing removed. Original communication restored."
|
|
25
|
+
echo ""
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# MeshSig — Unregister an agent
|
|
4
|
+
#
|
|
5
|
+
# Called when xrunly-api deprovisions an agent.
|
|
6
|
+
# Usage: bash unregister-agent.sh <client_name>
|
|
7
|
+
# ==============================================================================
|
|
8
|
+
|
|
9
|
+
CLIENT_NAME="$1"
|
|
10
|
+
if [ -z "$CLIENT_NAME" ]; then
|
|
11
|
+
echo '{"error":"client_name required"}'
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
IDENTITY_DIR="/opt/meshsig/identities"
|
|
16
|
+
identity_file="$IDENTITY_DIR/$CLIENT_NAME.json"
|
|
17
|
+
|
|
18
|
+
if [ -f "$identity_file" ]; then
|
|
19
|
+
rm -f "$identity_file"
|
|
20
|
+
echo "{\"unregistered\":true,\"client\":\"$CLIENT_NAME\"}"
|
|
21
|
+
else
|
|
22
|
+
echo "{\"not_found\":true,\"client\":\"$CLIENT_NAME\"}"
|
|
23
|
+
fi
|