@diegoaltoworks/talker 0.8.0 → 0.10.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/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.test.d.ts +2 -0
- package/dist/core/logger.test.d.ts.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +176 -4
- package/dist/index.mjs +170 -3
- package/dist/middleware/input-sanitize.d.ts +20 -0
- package/dist/middleware/input-sanitize.d.ts.map +1 -0
- package/dist/middleware/input-sanitize.test.d.ts +2 -0
- package/dist/middleware/input-sanitize.test.d.ts.map +1 -0
- package/dist/middleware/rate-limit.d.ts +27 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.test.d.ts +2 -0
- package/dist/middleware/rate-limit.test.d.ts.map +1 -0
- package/dist/middleware/twilio-signature.d.ts +32 -0
- package/dist/middleware/twilio-signature.d.ts.map +1 -0
- package/dist/middleware/twilio-signature.test.d.ts +2 -0
- package/dist/middleware/twilio-signature.test.d.ts.map +1 -0
- package/dist/routes/call/index.d.ts.map +1 -1
- package/dist/routes/call/processor.d.ts.map +1 -1
- package/dist/routes/sms/index.d.ts.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/core/logger.d.ts
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
* Structured JSON logger
|
|
3
3
|
*
|
|
4
4
|
* Silent during tests unless DEBUG=true.
|
|
5
|
+
* Automatically redacts phone numbers in structured log data.
|
|
5
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Redact a phone number, keeping only the last 4 digits.
|
|
9
|
+
* E.g. "+15551234567" -> "***4567"
|
|
10
|
+
*/
|
|
11
|
+
export declare function redactPhone(phone: string): string;
|
|
6
12
|
export declare const logger: {
|
|
7
13
|
info: (message: string, data?: Record<string, unknown>) => void;
|
|
8
14
|
warn: (message: string, data?: Record<string, unknown>) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AA+BD,eAAO,MAAM,MAAM;oBACD,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;oBACtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;qBACrC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/core/logger.test.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -58,5 +58,8 @@ export { persistFinalSession, persistSession } from "./db/persist";
|
|
|
58
58
|
export type { SessionRecord, MessageRecord } from "./db/sessions";
|
|
59
59
|
export { callRoutes } from "./routes/call";
|
|
60
60
|
export { smsRoutes } from "./routes/sms";
|
|
61
|
-
export { logger } from "./core/logger";
|
|
61
|
+
export { logger, redactPhone } from "./core/logger";
|
|
62
|
+
export { twilioSignatureMiddleware, validateTwilioSignature } from "./middleware/twilio-signature";
|
|
63
|
+
export { rateLimitMiddleware } from "./middleware/rate-limit";
|
|
64
|
+
export { inputSanitizeMiddleware } from "./middleware/input-sanitize";
|
|
62
65
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,GACR,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,WAAW,EACX,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAG5C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,GACR,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,WAAW,EACX,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAG5C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -86,6 +86,7 @@ __export(index_exports, {
|
|
|
86
86
|
getVoiceConfig: () => getVoiceConfig,
|
|
87
87
|
incrementNoSpeechRetries: () => incrementNoSpeechRetries,
|
|
88
88
|
initDbClient: () => initDbClient,
|
|
89
|
+
inputSanitizeMiddleware: () => inputSanitizeMiddleware,
|
|
89
90
|
loadFlowsFromDirectory: () => loadFlowsFromDirectory,
|
|
90
91
|
loadPhrases: () => loadPhrases,
|
|
91
92
|
logger: () => logger,
|
|
@@ -95,6 +96,8 @@ __export(index_exports, {
|
|
|
95
96
|
processFlow: () => processFlow,
|
|
96
97
|
processIncoming: () => processIncoming,
|
|
97
98
|
processOutgoing: () => processOutgoing,
|
|
99
|
+
rateLimitMiddleware: () => rateLimitMiddleware,
|
|
100
|
+
redactPhone: () => redactPhone,
|
|
98
101
|
resetNoSpeechRetries: () => resetNoSpeechRetries,
|
|
99
102
|
runMigrations: () => runMigrations,
|
|
100
103
|
sayTwiml: () => sayTwiml,
|
|
@@ -107,7 +110,9 @@ __export(index_exports, {
|
|
|
107
110
|
startCleanup: () => startCleanup,
|
|
108
111
|
stopCleanup: () => stopCleanup,
|
|
109
112
|
transferTwiml: () => transferTwiml,
|
|
110
|
-
|
|
113
|
+
twilioSignatureMiddleware: () => twilioSignatureMiddleware,
|
|
114
|
+
updateFlowParams: () => updateFlowParams,
|
|
115
|
+
validateTwilioSignature: () => validateTwilioSignature
|
|
111
116
|
});
|
|
112
117
|
module.exports = __toCommonJS(index_exports);
|
|
113
118
|
|
|
@@ -116,13 +121,31 @@ var isTestEnv = process.env.NODE_ENV === "test" || typeof Bun !== "undefined" &&
|
|
|
116
121
|
var isDebug = process.env.DEBUG === "true";
|
|
117
122
|
var isSilent = isTestEnv && !isDebug;
|
|
118
123
|
var timestamp = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
124
|
+
function redactPhone(phone) {
|
|
125
|
+
if (!phone || phone === "unknown") return phone;
|
|
126
|
+
const digits = phone.replace(/\D/g, "");
|
|
127
|
+
if (digits.length <= 4) return "***";
|
|
128
|
+
return `***${digits.slice(-4)}`;
|
|
129
|
+
}
|
|
130
|
+
function redactData(data) {
|
|
131
|
+
if (!data) return data;
|
|
132
|
+
const redacted = {};
|
|
133
|
+
for (const [key, value] of Object.entries(data)) {
|
|
134
|
+
if ((key === "phoneNumber" || key === "phone") && typeof value === "string") {
|
|
135
|
+
redacted[key] = redactPhone(value);
|
|
136
|
+
} else {
|
|
137
|
+
redacted[key] = value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return redacted;
|
|
141
|
+
}
|
|
119
142
|
var log = (level, message, data) => {
|
|
120
143
|
if (isSilent) return;
|
|
121
144
|
const entry = {
|
|
122
145
|
timestamp: timestamp(),
|
|
123
146
|
level,
|
|
124
147
|
message,
|
|
125
|
-
...data
|
|
148
|
+
...redactData(data)
|
|
126
149
|
};
|
|
127
150
|
console.log(JSON.stringify(entry));
|
|
128
151
|
};
|
|
@@ -553,6 +576,140 @@ function testModeDetectIntent(message) {
|
|
|
553
576
|
// src/routes/call/index.ts
|
|
554
577
|
var import_hono = require("hono");
|
|
555
578
|
|
|
579
|
+
// src/middleware/input-sanitize.ts
|
|
580
|
+
var DEFAULT_MAX_INPUT_LENGTH = 1e3;
|
|
581
|
+
function truncateInput(input, maxLength) {
|
|
582
|
+
if (input.length <= maxLength) return input;
|
|
583
|
+
return input.substring(0, maxLength);
|
|
584
|
+
}
|
|
585
|
+
function inputSanitizeMiddleware(maxInputLength) {
|
|
586
|
+
const maxLen = maxInputLength ?? DEFAULT_MAX_INPUT_LENGTH;
|
|
587
|
+
return async (c, next) => {
|
|
588
|
+
const body = await c.req.parseBody();
|
|
589
|
+
let truncated = false;
|
|
590
|
+
if (typeof body.SpeechResult === "string" && body.SpeechResult.length > maxLen) {
|
|
591
|
+
logger.warn("input truncated: SpeechResult", {
|
|
592
|
+
original: body.SpeechResult.length,
|
|
593
|
+
max: maxLen
|
|
594
|
+
});
|
|
595
|
+
body.SpeechResult = truncateInput(body.SpeechResult, maxLen);
|
|
596
|
+
truncated = true;
|
|
597
|
+
}
|
|
598
|
+
if (typeof body.Body === "string" && body.Body.length > maxLen) {
|
|
599
|
+
logger.warn("input truncated: Body", {
|
|
600
|
+
original: body.Body.length,
|
|
601
|
+
max: maxLen
|
|
602
|
+
});
|
|
603
|
+
body.Body = truncateInput(body.Body, maxLen);
|
|
604
|
+
truncated = true;
|
|
605
|
+
}
|
|
606
|
+
if (truncated) {
|
|
607
|
+
c.set("sanitizedBody", body);
|
|
608
|
+
}
|
|
609
|
+
return next();
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/middleware/rate-limit.ts
|
|
614
|
+
var DEFAULT_MAX_REQUESTS = 30;
|
|
615
|
+
var DEFAULT_WINDOW_MS = 6e4;
|
|
616
|
+
var rateLimitStore = /* @__PURE__ */ new Map();
|
|
617
|
+
var cleanupTimer2 = null;
|
|
618
|
+
function ensureCleanup(windowMs) {
|
|
619
|
+
if (cleanupTimer2) return;
|
|
620
|
+
cleanupTimer2 = setInterval(() => {
|
|
621
|
+
const cutoff = Date.now() - windowMs * 2;
|
|
622
|
+
for (const [key, entry] of rateLimitStore) {
|
|
623
|
+
entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
|
|
624
|
+
if (entry.timestamps.length === 0) {
|
|
625
|
+
rateLimitStore.delete(key);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}, windowMs);
|
|
629
|
+
}
|
|
630
|
+
function checkRateLimit(phoneNumber, maxRequests, windowMs) {
|
|
631
|
+
const now = Date.now();
|
|
632
|
+
const cutoff = now - windowMs;
|
|
633
|
+
let entry = rateLimitStore.get(phoneNumber);
|
|
634
|
+
if (!entry) {
|
|
635
|
+
entry = { timestamps: [] };
|
|
636
|
+
rateLimitStore.set(phoneNumber, entry);
|
|
637
|
+
}
|
|
638
|
+
entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
|
|
639
|
+
if (entry.timestamps.length >= maxRequests) {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
entry.timestamps.push(now);
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
function rateLimitMiddleware(config) {
|
|
646
|
+
const maxRequests = config?.maxRequests ?? DEFAULT_MAX_REQUESTS;
|
|
647
|
+
const windowMs = config?.windowMs ?? DEFAULT_WINDOW_MS;
|
|
648
|
+
ensureCleanup(windowMs);
|
|
649
|
+
return async (c, next) => {
|
|
650
|
+
const body = await c.req.parseBody();
|
|
651
|
+
const phoneNumber = (body.From || "unknown").trim();
|
|
652
|
+
if (!checkRateLimit(phoneNumber, maxRequests, windowMs)) {
|
|
653
|
+
logger.warn("rate limit exceeded", { phoneNumber, path: c.req.path });
|
|
654
|
+
const twiml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
655
|
+
<Response>
|
|
656
|
+
<Say>Please try again in a moment.</Say>
|
|
657
|
+
</Response>`;
|
|
658
|
+
return c.text(twiml, 429, { "Content-Type": "text/xml" });
|
|
659
|
+
}
|
|
660
|
+
return next();
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// src/middleware/twilio-signature.ts
|
|
665
|
+
var import_node_crypto = require("node:crypto");
|
|
666
|
+
function computeTwilioSignature(authToken, url, params) {
|
|
667
|
+
const sortedKeys = Object.keys(params).sort();
|
|
668
|
+
let data = url;
|
|
669
|
+
for (const key of sortedKeys) {
|
|
670
|
+
data += key + params[key];
|
|
671
|
+
}
|
|
672
|
+
return (0, import_node_crypto.createHmac)("sha1", authToken).update(data).digest("base64");
|
|
673
|
+
}
|
|
674
|
+
function validateTwilioSignature(authToken, signature, url, params) {
|
|
675
|
+
const expected = computeTwilioSignature(authToken, url, params);
|
|
676
|
+
if (expected.length !== signature.length) return false;
|
|
677
|
+
let mismatch = 0;
|
|
678
|
+
for (let i = 0; i < expected.length; i++) {
|
|
679
|
+
mismatch |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
|
|
680
|
+
}
|
|
681
|
+
return mismatch === 0;
|
|
682
|
+
}
|
|
683
|
+
function twilioSignatureMiddleware(authToken, baseUrl) {
|
|
684
|
+
return async (c, next) => {
|
|
685
|
+
if (!authToken) {
|
|
686
|
+
return next();
|
|
687
|
+
}
|
|
688
|
+
const signature = c.req.header("x-twilio-signature");
|
|
689
|
+
if (!signature) {
|
|
690
|
+
logger.warn("rejected request: missing X-Twilio-Signature header", {
|
|
691
|
+
path: c.req.path
|
|
692
|
+
});
|
|
693
|
+
return c.text("", 403);
|
|
694
|
+
}
|
|
695
|
+
const requestUrl = baseUrl ? `${baseUrl.replace(/\/$/, "")}${c.req.path}` : c.req.url;
|
|
696
|
+
const body = await c.req.parseBody();
|
|
697
|
+
const params = {};
|
|
698
|
+
for (const [key, value] of Object.entries(body)) {
|
|
699
|
+
if (typeof value === "string") {
|
|
700
|
+
params[key] = value;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (!validateTwilioSignature(authToken, signature, requestUrl, params)) {
|
|
704
|
+
logger.warn("rejected request: invalid Twilio signature", {
|
|
705
|
+
path: c.req.path
|
|
706
|
+
});
|
|
707
|
+
return c.text("", 403);
|
|
708
|
+
}
|
|
709
|
+
return next();
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
|
|
556
713
|
// src/core/errors.ts
|
|
557
714
|
function getErrorMessage(error) {
|
|
558
715
|
if (error instanceof Error) {
|
|
@@ -1488,9 +1645,10 @@ async function processCall(deps, registry, phoneNumber, speechResult) {
|
|
|
1488
1645
|
deps.config.voices
|
|
1489
1646
|
);
|
|
1490
1647
|
const transferNumber = deps.config.transferNumber || "";
|
|
1648
|
+
const escapedFlowResponse = escapeXml(flowResult.response);
|
|
1491
1649
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1492
1650
|
<Response>
|
|
1493
|
-
<Say voice="${voice}" language="${lang}">${
|
|
1651
|
+
<Say voice="${voice}" language="${lang}">${escapedFlowResponse}</Say>
|
|
1494
1652
|
<Dial>${transferNumber}</Dial>
|
|
1495
1653
|
</Response>`;
|
|
1496
1654
|
}
|
|
@@ -1583,6 +1741,12 @@ async function handleStatus(c) {
|
|
|
1583
1741
|
// src/routes/call/index.ts
|
|
1584
1742
|
function callRoutes(deps, registry) {
|
|
1585
1743
|
const app = new import_hono.Hono();
|
|
1744
|
+
app.use("/call/*", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1745
|
+
app.use("/call/*", rateLimitMiddleware(deps.config.rateLimit));
|
|
1746
|
+
app.use("/call/*", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1747
|
+
app.post("/call", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1748
|
+
app.post("/call", rateLimitMiddleware(deps.config.rateLimit));
|
|
1749
|
+
app.post("/call", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1586
1750
|
app.post("/call", (c) => handleInitialCall(c, deps.config));
|
|
1587
1751
|
app.post("/call/respond", (c) => handleRespond(c, deps, registry));
|
|
1588
1752
|
app.post("/call/answer", (c) => handleAnswer(c, deps.config));
|
|
@@ -1653,6 +1817,9 @@ async function handleIncomingSMS(c, deps, registry) {
|
|
|
1653
1817
|
// src/routes/sms/index.ts
|
|
1654
1818
|
function smsRoutes(deps, registry) {
|
|
1655
1819
|
const app = new import_hono2.Hono();
|
|
1820
|
+
app.post("/sms", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1821
|
+
app.post("/sms", rateLimitMiddleware(deps.config.rateLimit));
|
|
1822
|
+
app.post("/sms", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1656
1823
|
app.post("/sms", (c) => handleIncomingSMS(c, deps, registry));
|
|
1657
1824
|
app.get("/sms", (c) => c.text("SMS endpoint active"));
|
|
1658
1825
|
return app;
|
|
@@ -1815,6 +1982,7 @@ async function sendSMS(config, to, message) {
|
|
|
1815
1982
|
getVoiceConfig,
|
|
1816
1983
|
incrementNoSpeechRetries,
|
|
1817
1984
|
initDbClient,
|
|
1985
|
+
inputSanitizeMiddleware,
|
|
1818
1986
|
loadFlowsFromDirectory,
|
|
1819
1987
|
loadPhrases,
|
|
1820
1988
|
logger,
|
|
@@ -1824,6 +1992,8 @@ async function sendSMS(config, to, message) {
|
|
|
1824
1992
|
processFlow,
|
|
1825
1993
|
processIncoming,
|
|
1826
1994
|
processOutgoing,
|
|
1995
|
+
rateLimitMiddleware,
|
|
1996
|
+
redactPhone,
|
|
1827
1997
|
resetNoSpeechRetries,
|
|
1828
1998
|
runMigrations,
|
|
1829
1999
|
sayTwiml,
|
|
@@ -1836,5 +2006,7 @@ async function sendSMS(config, to, message) {
|
|
|
1836
2006
|
startCleanup,
|
|
1837
2007
|
stopCleanup,
|
|
1838
2008
|
transferTwiml,
|
|
1839
|
-
|
|
2009
|
+
twilioSignatureMiddleware,
|
|
2010
|
+
updateFlowParams,
|
|
2011
|
+
validateTwilioSignature
|
|
1840
2012
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -48,13 +48,31 @@ var isTestEnv = process.env.NODE_ENV === "test" || typeof Bun !== "undefined" &&
|
|
|
48
48
|
var isDebug = process.env.DEBUG === "true";
|
|
49
49
|
var isSilent = isTestEnv && !isDebug;
|
|
50
50
|
var timestamp = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
51
|
+
function redactPhone(phone) {
|
|
52
|
+
if (!phone || phone === "unknown") return phone;
|
|
53
|
+
const digits = phone.replace(/\D/g, "");
|
|
54
|
+
if (digits.length <= 4) return "***";
|
|
55
|
+
return `***${digits.slice(-4)}`;
|
|
56
|
+
}
|
|
57
|
+
function redactData(data) {
|
|
58
|
+
if (!data) return data;
|
|
59
|
+
const redacted = {};
|
|
60
|
+
for (const [key, value] of Object.entries(data)) {
|
|
61
|
+
if ((key === "phoneNumber" || key === "phone") && typeof value === "string") {
|
|
62
|
+
redacted[key] = redactPhone(value);
|
|
63
|
+
} else {
|
|
64
|
+
redacted[key] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return redacted;
|
|
68
|
+
}
|
|
51
69
|
var log = (level, message, data) => {
|
|
52
70
|
if (isSilent) return;
|
|
53
71
|
const entry = {
|
|
54
72
|
timestamp: timestamp(),
|
|
55
73
|
level,
|
|
56
74
|
message,
|
|
57
|
-
...data
|
|
75
|
+
...redactData(data)
|
|
58
76
|
};
|
|
59
77
|
console.log(JSON.stringify(entry));
|
|
60
78
|
};
|
|
@@ -485,6 +503,140 @@ function testModeDetectIntent(message) {
|
|
|
485
503
|
// src/routes/call/index.ts
|
|
486
504
|
import { Hono } from "hono";
|
|
487
505
|
|
|
506
|
+
// src/middleware/input-sanitize.ts
|
|
507
|
+
var DEFAULT_MAX_INPUT_LENGTH = 1e3;
|
|
508
|
+
function truncateInput(input, maxLength) {
|
|
509
|
+
if (input.length <= maxLength) return input;
|
|
510
|
+
return input.substring(0, maxLength);
|
|
511
|
+
}
|
|
512
|
+
function inputSanitizeMiddleware(maxInputLength) {
|
|
513
|
+
const maxLen = maxInputLength ?? DEFAULT_MAX_INPUT_LENGTH;
|
|
514
|
+
return async (c, next) => {
|
|
515
|
+
const body = await c.req.parseBody();
|
|
516
|
+
let truncated = false;
|
|
517
|
+
if (typeof body.SpeechResult === "string" && body.SpeechResult.length > maxLen) {
|
|
518
|
+
logger.warn("input truncated: SpeechResult", {
|
|
519
|
+
original: body.SpeechResult.length,
|
|
520
|
+
max: maxLen
|
|
521
|
+
});
|
|
522
|
+
body.SpeechResult = truncateInput(body.SpeechResult, maxLen);
|
|
523
|
+
truncated = true;
|
|
524
|
+
}
|
|
525
|
+
if (typeof body.Body === "string" && body.Body.length > maxLen) {
|
|
526
|
+
logger.warn("input truncated: Body", {
|
|
527
|
+
original: body.Body.length,
|
|
528
|
+
max: maxLen
|
|
529
|
+
});
|
|
530
|
+
body.Body = truncateInput(body.Body, maxLen);
|
|
531
|
+
truncated = true;
|
|
532
|
+
}
|
|
533
|
+
if (truncated) {
|
|
534
|
+
c.set("sanitizedBody", body);
|
|
535
|
+
}
|
|
536
|
+
return next();
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// src/middleware/rate-limit.ts
|
|
541
|
+
var DEFAULT_MAX_REQUESTS = 30;
|
|
542
|
+
var DEFAULT_WINDOW_MS = 6e4;
|
|
543
|
+
var rateLimitStore = /* @__PURE__ */ new Map();
|
|
544
|
+
var cleanupTimer2 = null;
|
|
545
|
+
function ensureCleanup(windowMs) {
|
|
546
|
+
if (cleanupTimer2) return;
|
|
547
|
+
cleanupTimer2 = setInterval(() => {
|
|
548
|
+
const cutoff = Date.now() - windowMs * 2;
|
|
549
|
+
for (const [key, entry] of rateLimitStore) {
|
|
550
|
+
entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
|
|
551
|
+
if (entry.timestamps.length === 0) {
|
|
552
|
+
rateLimitStore.delete(key);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}, windowMs);
|
|
556
|
+
}
|
|
557
|
+
function checkRateLimit(phoneNumber, maxRequests, windowMs) {
|
|
558
|
+
const now = Date.now();
|
|
559
|
+
const cutoff = now - windowMs;
|
|
560
|
+
let entry = rateLimitStore.get(phoneNumber);
|
|
561
|
+
if (!entry) {
|
|
562
|
+
entry = { timestamps: [] };
|
|
563
|
+
rateLimitStore.set(phoneNumber, entry);
|
|
564
|
+
}
|
|
565
|
+
entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
|
|
566
|
+
if (entry.timestamps.length >= maxRequests) {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
entry.timestamps.push(now);
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
function rateLimitMiddleware(config) {
|
|
573
|
+
const maxRequests = config?.maxRequests ?? DEFAULT_MAX_REQUESTS;
|
|
574
|
+
const windowMs = config?.windowMs ?? DEFAULT_WINDOW_MS;
|
|
575
|
+
ensureCleanup(windowMs);
|
|
576
|
+
return async (c, next) => {
|
|
577
|
+
const body = await c.req.parseBody();
|
|
578
|
+
const phoneNumber = (body.From || "unknown").trim();
|
|
579
|
+
if (!checkRateLimit(phoneNumber, maxRequests, windowMs)) {
|
|
580
|
+
logger.warn("rate limit exceeded", { phoneNumber, path: c.req.path });
|
|
581
|
+
const twiml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
582
|
+
<Response>
|
|
583
|
+
<Say>Please try again in a moment.</Say>
|
|
584
|
+
</Response>`;
|
|
585
|
+
return c.text(twiml, 429, { "Content-Type": "text/xml" });
|
|
586
|
+
}
|
|
587
|
+
return next();
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/middleware/twilio-signature.ts
|
|
592
|
+
import { createHmac } from "node:crypto";
|
|
593
|
+
function computeTwilioSignature(authToken, url, params) {
|
|
594
|
+
const sortedKeys = Object.keys(params).sort();
|
|
595
|
+
let data = url;
|
|
596
|
+
for (const key of sortedKeys) {
|
|
597
|
+
data += key + params[key];
|
|
598
|
+
}
|
|
599
|
+
return createHmac("sha1", authToken).update(data).digest("base64");
|
|
600
|
+
}
|
|
601
|
+
function validateTwilioSignature(authToken, signature, url, params) {
|
|
602
|
+
const expected = computeTwilioSignature(authToken, url, params);
|
|
603
|
+
if (expected.length !== signature.length) return false;
|
|
604
|
+
let mismatch = 0;
|
|
605
|
+
for (let i = 0; i < expected.length; i++) {
|
|
606
|
+
mismatch |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
|
|
607
|
+
}
|
|
608
|
+
return mismatch === 0;
|
|
609
|
+
}
|
|
610
|
+
function twilioSignatureMiddleware(authToken, baseUrl) {
|
|
611
|
+
return async (c, next) => {
|
|
612
|
+
if (!authToken) {
|
|
613
|
+
return next();
|
|
614
|
+
}
|
|
615
|
+
const signature = c.req.header("x-twilio-signature");
|
|
616
|
+
if (!signature) {
|
|
617
|
+
logger.warn("rejected request: missing X-Twilio-Signature header", {
|
|
618
|
+
path: c.req.path
|
|
619
|
+
});
|
|
620
|
+
return c.text("", 403);
|
|
621
|
+
}
|
|
622
|
+
const requestUrl = baseUrl ? `${baseUrl.replace(/\/$/, "")}${c.req.path}` : c.req.url;
|
|
623
|
+
const body = await c.req.parseBody();
|
|
624
|
+
const params = {};
|
|
625
|
+
for (const [key, value] of Object.entries(body)) {
|
|
626
|
+
if (typeof value === "string") {
|
|
627
|
+
params[key] = value;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (!validateTwilioSignature(authToken, signature, requestUrl, params)) {
|
|
631
|
+
logger.warn("rejected request: invalid Twilio signature", {
|
|
632
|
+
path: c.req.path
|
|
633
|
+
});
|
|
634
|
+
return c.text("", 403);
|
|
635
|
+
}
|
|
636
|
+
return next();
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
488
640
|
// src/core/errors.ts
|
|
489
641
|
function getErrorMessage(error) {
|
|
490
642
|
if (error instanceof Error) {
|
|
@@ -1420,9 +1572,10 @@ async function processCall(deps, registry, phoneNumber, speechResult) {
|
|
|
1420
1572
|
deps.config.voices
|
|
1421
1573
|
);
|
|
1422
1574
|
const transferNumber = deps.config.transferNumber || "";
|
|
1575
|
+
const escapedFlowResponse = escapeXml(flowResult.response);
|
|
1423
1576
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1424
1577
|
<Response>
|
|
1425
|
-
<Say voice="${voice}" language="${lang}">${
|
|
1578
|
+
<Say voice="${voice}" language="${lang}">${escapedFlowResponse}</Say>
|
|
1426
1579
|
<Dial>${transferNumber}</Dial>
|
|
1427
1580
|
</Response>`;
|
|
1428
1581
|
}
|
|
@@ -1515,6 +1668,12 @@ async function handleStatus(c) {
|
|
|
1515
1668
|
// src/routes/call/index.ts
|
|
1516
1669
|
function callRoutes(deps, registry) {
|
|
1517
1670
|
const app = new Hono();
|
|
1671
|
+
app.use("/call/*", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1672
|
+
app.use("/call/*", rateLimitMiddleware(deps.config.rateLimit));
|
|
1673
|
+
app.use("/call/*", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1674
|
+
app.post("/call", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1675
|
+
app.post("/call", rateLimitMiddleware(deps.config.rateLimit));
|
|
1676
|
+
app.post("/call", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1518
1677
|
app.post("/call", (c) => handleInitialCall(c, deps.config));
|
|
1519
1678
|
app.post("/call/respond", (c) => handleRespond(c, deps, registry));
|
|
1520
1679
|
app.post("/call/answer", (c) => handleAnswer(c, deps.config));
|
|
@@ -1585,6 +1744,9 @@ async function handleIncomingSMS(c, deps, registry) {
|
|
|
1585
1744
|
// src/routes/sms/index.ts
|
|
1586
1745
|
function smsRoutes(deps, registry) {
|
|
1587
1746
|
const app = new Hono2();
|
|
1747
|
+
app.post("/sms", twilioSignatureMiddleware(deps.config.twilio?.authToken));
|
|
1748
|
+
app.post("/sms", rateLimitMiddleware(deps.config.rateLimit));
|
|
1749
|
+
app.post("/sms", inputSanitizeMiddleware(deps.config.maxInputLength));
|
|
1588
1750
|
app.post("/sms", (c) => handleIncomingSMS(c, deps, registry));
|
|
1589
1751
|
app.get("/sms", (c) => c.text("SMS endpoint active"));
|
|
1590
1752
|
return app;
|
|
@@ -1746,6 +1908,7 @@ export {
|
|
|
1746
1908
|
getVoiceConfig,
|
|
1747
1909
|
incrementNoSpeechRetries,
|
|
1748
1910
|
initDbClient,
|
|
1911
|
+
inputSanitizeMiddleware,
|
|
1749
1912
|
loadFlowsFromDirectory,
|
|
1750
1913
|
loadPhrases,
|
|
1751
1914
|
logger,
|
|
@@ -1755,6 +1918,8 @@ export {
|
|
|
1755
1918
|
processFlow,
|
|
1756
1919
|
processIncoming,
|
|
1757
1920
|
processOutgoing,
|
|
1921
|
+
rateLimitMiddleware,
|
|
1922
|
+
redactPhone,
|
|
1758
1923
|
resetNoSpeechRetries,
|
|
1759
1924
|
runMigrations,
|
|
1760
1925
|
sayTwiml,
|
|
@@ -1767,5 +1932,7 @@ export {
|
|
|
1767
1932
|
startCleanup,
|
|
1768
1933
|
stopCleanup,
|
|
1769
1934
|
transferTwiml,
|
|
1770
|
-
|
|
1935
|
+
twilioSignatureMiddleware,
|
|
1936
|
+
updateFlowParams,
|
|
1937
|
+
validateTwilioSignature
|
|
1771
1938
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Sanitization Middleware
|
|
3
|
+
*
|
|
4
|
+
* Enforces a maximum length on user-supplied input fields (SpeechResult, Body).
|
|
5
|
+
* Truncates silently rather than rejecting, since Twilio expects a TwiML response.
|
|
6
|
+
*/
|
|
7
|
+
import type { Context, Next } from "hono";
|
|
8
|
+
/**
|
|
9
|
+
* Truncate a string to the max length, appending an ellipsis if truncated.
|
|
10
|
+
*/
|
|
11
|
+
export declare function truncateInput(input: string, maxLength: number): string;
|
|
12
|
+
/**
|
|
13
|
+
* Hono middleware factory for input sanitization.
|
|
14
|
+
*
|
|
15
|
+
* Intercepts the request body and truncates SpeechResult and Body fields
|
|
16
|
+
* to the configured maximum length. Stores the sanitized values on the
|
|
17
|
+
* context so downstream handlers see the truncated values.
|
|
18
|
+
*/
|
|
19
|
+
export declare function inputSanitizeMiddleware(maxInputLength?: number): (c: Context, next: Next) => Promise<void>;
|
|
20
|
+
//# sourceMappingURL=input-sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-sanitize.d.ts","sourceRoot":"","sources":["../../src/middleware/input-sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,CAAC,EAAE,MAAM,IAG/C,GAAG,OAAO,EAAE,MAAM,IAAI,mBA6BrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-sanitize.test.d.ts","sourceRoot":"","sources":["../../src/middleware/input-sanitize.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiting Middleware
|
|
3
|
+
*
|
|
4
|
+
* Sliding-window rate limiter keyed by caller phone number.
|
|
5
|
+
* Prevents abuse by limiting requests per phone number within a time window.
|
|
6
|
+
*/
|
|
7
|
+
import type { Context, Next } from "hono";
|
|
8
|
+
/**
|
|
9
|
+
* Check if a phone number has exceeded the rate limit.
|
|
10
|
+
* Returns true if the request should be allowed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkRateLimit(phoneNumber: string, maxRequests: number, windowMs: number): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Hono middleware factory for rate limiting.
|
|
15
|
+
*
|
|
16
|
+
* Limits requests per phone number (from body.From).
|
|
17
|
+
* Returns a 429 TwiML response when the limit is exceeded.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rateLimitMiddleware(config?: {
|
|
20
|
+
maxRequests?: number;
|
|
21
|
+
windowMs?: number;
|
|
22
|
+
}): (c: Context, next: Next) => Promise<void | (Response & import("hono").TypedResponse<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Say>Please try again in a moment.</Say>\n</Response>", 429, "text">)>;
|
|
23
|
+
/**
|
|
24
|
+
* Reset rate limit store (for testing)
|
|
25
|
+
*/
|
|
26
|
+
export declare function resetRateLimitStore(): void;
|
|
27
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA4B1C;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAmBT;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,IAMxE,GAAG,OAAO,EAAE,MAAM,IAAI,iMAerC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.test.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Twilio Webhook Signature Validation Middleware
|
|
3
|
+
*
|
|
4
|
+
* Validates that incoming requests are genuinely from Twilio by verifying
|
|
5
|
+
* the X-Twilio-Signature header using HMAC-SHA1 per Twilio's spec.
|
|
6
|
+
*
|
|
7
|
+
* @see https://www.twilio.com/docs/usage/security#validating-requests
|
|
8
|
+
*/
|
|
9
|
+
import type { Context, Next } from "hono";
|
|
10
|
+
/**
|
|
11
|
+
* Compute the expected Twilio signature for a request.
|
|
12
|
+
*
|
|
13
|
+
* Algorithm (per Twilio docs):
|
|
14
|
+
* 1. Take the full URL of the request
|
|
15
|
+
* 2. Sort POST body params alphabetically by key
|
|
16
|
+
* 3. Append each key-value pair to the URL (no separators)
|
|
17
|
+
* 4. HMAC-SHA1 the result with the auth token, then Base64 encode
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeTwilioSignature(authToken: string, url: string, params: Record<string, string>): string;
|
|
20
|
+
/**
|
|
21
|
+
* Validate a Twilio request signature
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateTwilioSignature(authToken: string, signature: string, url: string, params: Record<string, string>): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Hono middleware factory for Twilio signature validation.
|
|
26
|
+
*
|
|
27
|
+
* When authToken is provided, rejects any request without a valid
|
|
28
|
+
* X-Twilio-Signature header. When authToken is not configured,
|
|
29
|
+
* the middleware is a pass-through (allows development/testing without Twilio).
|
|
30
|
+
*/
|
|
31
|
+
export declare function twilioSignatureMiddleware(authToken?: string, baseUrl?: string): (c: Context, next: Next) => Promise<void | (Response & import("hono").TypedResponse<"", 403, "text">)>;
|
|
32
|
+
//# sourceMappingURL=twilio-signature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twilio-signature.d.ts","sourceRoot":"","sources":["../../src/middleware/twilio-signature.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG1C;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,IAC9D,GAAG,OAAO,EAAE,MAAM,IAAI,gFAkCrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twilio-signature.test.d.ts","sourceRoot":"","sources":["../../src/middleware/twilio-signature.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/call/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/call/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOtD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,8EAoB1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../../../src/routes/call/processor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../../../src/routes/call/processor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CA8DjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/sms/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/sms/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,8EAYzE"}
|
package/dist/types.d.ts
CHANGED
|
@@ -98,6 +98,15 @@ export interface TalkerConfig {
|
|
|
98
98
|
cleanupIntervalMs?: number;
|
|
99
99
|
/** Maximum no-speech retries before ending call. Default: 3 */
|
|
100
100
|
maxNoSpeechRetries?: number;
|
|
101
|
+
/** Rate limiting configuration */
|
|
102
|
+
rateLimit?: {
|
|
103
|
+
/** Max requests per window per phone number. Default: 30 */
|
|
104
|
+
maxRequests?: number;
|
|
105
|
+
/** Window size in milliseconds. Default: 60000 (1 minute) */
|
|
106
|
+
windowMs?: number;
|
|
107
|
+
};
|
|
108
|
+
/** Maximum input length for speech/SMS messages in characters. Default: 1000 */
|
|
109
|
+
maxInputLength?: number;
|
|
101
110
|
/** Chat function override. By default, talker queries chatter's RAG pipeline directly */
|
|
102
111
|
chatFn?: (phoneNumber: string, message: string) => Promise<string>;
|
|
103
112
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,6BAA6B,CAAC,EAAE,OAAO,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAErC,qHAAqH;IACrH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wCAAwC;IACxC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAE9B,oBAAoB;IACpB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAEjC,uGAAuG;IACvG,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,uGAAuG;IACvG,QAAQ,CAAC,EAAE;QACT,gCAAgC;QAChC,GAAG,EAAE,MAAM,CAAC;QACZ,uBAAuB;QACvB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,kCAAkC;IAClC,SAAS,CAAC,EAAE;QACV,4DAA4D;QAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,6DAA6D;QAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,yFAAyF;IACzF,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACpE;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,OAAO,EAAE,kBAAkB,CAAC;IAC5B,oCAAoC;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,aAAa,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,kBAAkB,KACxB,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEhC,MAAM,MAAM,WAAW,GAAG,CACxB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7B,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,WAAW,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1F,UAAU,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE;QACJ,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,GAAG,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegoaltoworks/talker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Telephony plugin for Chatter — adds voice call and SMS support via Twilio",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@biomejs/biome": "^1.9.4",
|
|
88
|
-
"@diegoaltoworks/chatter": "^0.
|
|
89
|
-
"@libsql/client": "^0.
|
|
88
|
+
"@diegoaltoworks/chatter": "^0.10.0",
|
|
89
|
+
"@libsql/client": "^0.17.0",
|
|
90
90
|
"@types/bun": "^1.1.12",
|
|
91
91
|
"@types/node": "^22.9.1",
|
|
92
92
|
"esbuild": "^0.27.4",
|