@fidacy/mcp 0.1.7 → 0.1.8

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/core.js CHANGED
@@ -95,6 +95,50 @@ var FileAuditStore = class {
95
95
  };
96
96
 
97
97
  // ../firewall/dist/evaluate.js
98
+ function fold(s) {
99
+ return s.toLowerCase().replace(/[4@]/g, "a").replace(/[0]/g, "o").replace(/[1|!]/g, "l").replace(/[3]/g, "e").replace(/[5$]/g, "s").replace(/[7]/g, "t").replace(/[^a-z0-9]/g, "");
100
+ }
101
+ function lev(a, b, max) {
102
+ if (Math.abs(a.length - b.length) > max)
103
+ return max + 1;
104
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
105
+ for (let i = 1; i <= a.length; i++) {
106
+ const cur = [i];
107
+ let rowMin = i;
108
+ for (let j = 1; j <= b.length; j++) {
109
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
110
+ const v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
111
+ cur[j] = v;
112
+ if (v < rowMin)
113
+ rowMin = v;
114
+ }
115
+ if (rowMin > max)
116
+ return max + 1;
117
+ prev = cur;
118
+ }
119
+ return prev[b.length];
120
+ }
121
+ function lookalikePayee(payee, allowed) {
122
+ const exact = new Set(allowed);
123
+ if (exact.has(payee) || allowed.includes("*"))
124
+ return null;
125
+ const pf = fold(payee);
126
+ if (pf.length < 4)
127
+ return null;
128
+ for (const a of allowed) {
129
+ if (a === "*")
130
+ continue;
131
+ const af = fold(a);
132
+ if (af.length < 4)
133
+ continue;
134
+ if (pf === af)
135
+ return a;
136
+ const d = lev(pf, af, 2);
137
+ if (d > 0 && d <= 2)
138
+ return a;
139
+ }
140
+ return null;
141
+ }
98
142
  function evaluate(mandate, req, spentSoFar) {
99
143
  const now = Date.now();
100
144
  if (mandate.revoked)
@@ -112,8 +156,12 @@ function evaluate(mandate, req, spentSoFar) {
112
156
  if (spentSoFar + req.amount > mandate.allow.maxTotal)
113
157
  return `total_cap_exceeded:${spentSoFar + req.amount}>${mandate.allow.maxTotal}`;
114
158
  const payeeOk = mandate.allow.payees.includes("*") || mandate.allow.payees.includes(req.payee);
115
- if (!payeeOk)
159
+ if (!payeeOk) {
160
+ const impersonated = lookalikePayee(req.payee, mandate.allow.payees);
161
+ if (impersonated)
162
+ return `payee_lookalike:${req.payee}~${impersonated}`;
116
163
  return `payee_not_in_allowlist:${req.payee}`;
164
+ }
117
165
  const catOk = mandate.allow.categories.includes("*") || mandate.allow.categories.includes(req.category);
118
166
  if (!catOk)
119
167
  return `category_not_allowed:${req.category}`;
package/dist/index.js CHANGED
@@ -102,6 +102,50 @@ var FileAuditStore = class {
102
102
  };
103
103
 
104
104
  // ../firewall/dist/evaluate.js
105
+ function fold(s) {
106
+ return s.toLowerCase().replace(/[4@]/g, "a").replace(/[0]/g, "o").replace(/[1|!]/g, "l").replace(/[3]/g, "e").replace(/[5$]/g, "s").replace(/[7]/g, "t").replace(/[^a-z0-9]/g, "");
107
+ }
108
+ function lev(a, b, max) {
109
+ if (Math.abs(a.length - b.length) > max)
110
+ return max + 1;
111
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
112
+ for (let i = 1; i <= a.length; i++) {
113
+ const cur = [i];
114
+ let rowMin = i;
115
+ for (let j = 1; j <= b.length; j++) {
116
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
117
+ const v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
118
+ cur[j] = v;
119
+ if (v < rowMin)
120
+ rowMin = v;
121
+ }
122
+ if (rowMin > max)
123
+ return max + 1;
124
+ prev = cur;
125
+ }
126
+ return prev[b.length];
127
+ }
128
+ function lookalikePayee(payee, allowed) {
129
+ const exact = new Set(allowed);
130
+ if (exact.has(payee) || allowed.includes("*"))
131
+ return null;
132
+ const pf = fold(payee);
133
+ if (pf.length < 4)
134
+ return null;
135
+ for (const a of allowed) {
136
+ if (a === "*")
137
+ continue;
138
+ const af = fold(a);
139
+ if (af.length < 4)
140
+ continue;
141
+ if (pf === af)
142
+ return a;
143
+ const d = lev(pf, af, 2);
144
+ if (d > 0 && d <= 2)
145
+ return a;
146
+ }
147
+ return null;
148
+ }
105
149
  function evaluate(mandate, req, spentSoFar) {
106
150
  const now = Date.now();
107
151
  if (mandate.revoked)
@@ -119,8 +163,12 @@ function evaluate(mandate, req, spentSoFar) {
119
163
  if (spentSoFar + req.amount > mandate.allow.maxTotal)
120
164
  return `total_cap_exceeded:${spentSoFar + req.amount}>${mandate.allow.maxTotal}`;
121
165
  const payeeOk = mandate.allow.payees.includes("*") || mandate.allow.payees.includes(req.payee);
122
- if (!payeeOk)
166
+ if (!payeeOk) {
167
+ const impersonated = lookalikePayee(req.payee, mandate.allow.payees);
168
+ if (impersonated)
169
+ return `payee_lookalike:${req.payee}~${impersonated}`;
123
170
  return `payee_not_in_allowlist:${req.payee}`;
171
+ }
124
172
  const catOk = mandate.allow.categories.includes("*") || mandate.allow.categories.includes(req.category);
125
173
  if (!catOk)
126
174
  return `category_not_allowed:${req.category}`;
package/dist/lib.js CHANGED
@@ -190,6 +190,50 @@ var GrantEnforcingExecutor = class {
190
190
  };
191
191
 
192
192
  // ../firewall/dist/evaluate.js
193
+ function fold(s) {
194
+ return s.toLowerCase().replace(/[4@]/g, "a").replace(/[0]/g, "o").replace(/[1|!]/g, "l").replace(/[3]/g, "e").replace(/[5$]/g, "s").replace(/[7]/g, "t").replace(/[^a-z0-9]/g, "");
195
+ }
196
+ function lev(a, b, max) {
197
+ if (Math.abs(a.length - b.length) > max)
198
+ return max + 1;
199
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
200
+ for (let i = 1; i <= a.length; i++) {
201
+ const cur = [i];
202
+ let rowMin = i;
203
+ for (let j = 1; j <= b.length; j++) {
204
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
205
+ const v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
206
+ cur[j] = v;
207
+ if (v < rowMin)
208
+ rowMin = v;
209
+ }
210
+ if (rowMin > max)
211
+ return max + 1;
212
+ prev = cur;
213
+ }
214
+ return prev[b.length];
215
+ }
216
+ function lookalikePayee(payee, allowed) {
217
+ const exact = new Set(allowed);
218
+ if (exact.has(payee) || allowed.includes("*"))
219
+ return null;
220
+ const pf = fold(payee);
221
+ if (pf.length < 4)
222
+ return null;
223
+ for (const a of allowed) {
224
+ if (a === "*")
225
+ continue;
226
+ const af = fold(a);
227
+ if (af.length < 4)
228
+ continue;
229
+ if (pf === af)
230
+ return a;
231
+ const d = lev(pf, af, 2);
232
+ if (d > 0 && d <= 2)
233
+ return a;
234
+ }
235
+ return null;
236
+ }
193
237
  function evaluate(mandate, req, spentSoFar) {
194
238
  const now = Date.now();
195
239
  if (mandate.revoked)
@@ -207,8 +251,12 @@ function evaluate(mandate, req, spentSoFar) {
207
251
  if (spentSoFar + req.amount > mandate.allow.maxTotal)
208
252
  return `total_cap_exceeded:${spentSoFar + req.amount}>${mandate.allow.maxTotal}`;
209
253
  const payeeOk = mandate.allow.payees.includes("*") || mandate.allow.payees.includes(req.payee);
210
- if (!payeeOk)
254
+ if (!payeeOk) {
255
+ const impersonated = lookalikePayee(req.payee, mandate.allow.payees);
256
+ if (impersonated)
257
+ return `payee_lookalike:${req.payee}~${impersonated}`;
211
258
  return `payee_not_in_allowlist:${req.payee}`;
259
+ }
212
260
  const catOk = mandate.allow.categories.includes("*") || mandate.allow.categories.includes(req.category);
213
261
  if (!catOk)
214
262
  return `category_not_allowed:${req.category}`;
@@ -515,6 +563,7 @@ export {
515
563
  canonInvoice,
516
564
  evaluate,
517
565
  loadOrGenerateKeyPair,
566
+ lookalikePayee,
518
567
  makeCore,
519
568
  publicKeyPem,
520
569
  requireHttpsBase,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fidacy/mcp",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Fidacy action firewall for AI agents. Mandate-gated payment authorization as an MCP server.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://fidacy.com",