@riocrypto/common-server 1.0.2695 → 1.0.2698

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/build/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from "./middlewares/require-min-admin-role";
9
9
  export * from "./middlewares/verify-csrf-token";
10
10
  export * from "./middlewares/dynamic-rate-limiter";
11
11
  export * from "./middlewares/auth-context";
12
+ export * from "./middlewares/verify-turnstile";
12
13
  export * from "./services/apiKey";
13
14
  export * from "./services/password";
14
15
  export * from "./services/logger";
@@ -111,6 +112,10 @@ export * from "./models/approved-alternative-bank-account-holder-name";
111
112
  export * from "./models/liquidity-sourcing-plan";
112
113
  export * from "./models/liquidity-sourcing-exclusion";
113
114
  export * from "./models/liquidity-sourcing-settings";
115
+ export * from "./models/compliance-session";
116
+ export * from "./models/compliance-bot-chat";
117
+ export * from "./models/compliance-bot-rule";
118
+ export * from "./models/compliance-bot-rule-result";
114
119
  export * from "./clients/axios-with-logging";
115
120
  export * from "./clients/slack-client";
116
121
  export * from "./clients/fireblocks-client";
package/build/index.js CHANGED
@@ -25,6 +25,7 @@ __exportStar(require("./middlewares/require-min-admin-role"), exports);
25
25
  __exportStar(require("./middlewares/verify-csrf-token"), exports);
26
26
  __exportStar(require("./middlewares/dynamic-rate-limiter"), exports);
27
27
  __exportStar(require("./middlewares/auth-context"), exports);
28
+ __exportStar(require("./middlewares/verify-turnstile"), exports);
28
29
  __exportStar(require("./services/apiKey"), exports);
29
30
  __exportStar(require("./services/password"), exports);
30
31
  __exportStar(require("./services/logger"), exports);
@@ -127,6 +128,10 @@ __exportStar(require("./models/approved-alternative-bank-account-holder-name"),
127
128
  __exportStar(require("./models/liquidity-sourcing-plan"), exports);
128
129
  __exportStar(require("./models/liquidity-sourcing-exclusion"), exports);
129
130
  __exportStar(require("./models/liquidity-sourcing-settings"), exports);
131
+ __exportStar(require("./models/compliance-session"), exports);
132
+ __exportStar(require("./models/compliance-bot-chat"), exports);
133
+ __exportStar(require("./models/compliance-bot-rule"), exports);
134
+ __exportStar(require("./models/compliance-bot-rule-result"), exports);
130
135
  __exportStar(require("./clients/axios-with-logging"), exports);
131
136
  __exportStar(require("./clients/slack-client"), exports);
132
137
  __exportStar(require("./clients/fireblocks-client"), exports);
@@ -0,0 +1,44 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ interface TurnstileConfig {
3
+ /**
4
+ * The Turnstile secret key (from Cloudflare dashboard)
5
+ * Can be obtained from: https://dash.cloudflare.com/?to=/:account/turnstile
6
+ */
7
+ secretKey: string;
8
+ /**
9
+ * Field name in request body that contains the turnstile token
10
+ * Default: "turnstileToken"
11
+ */
12
+ tokenField?: string;
13
+ /**
14
+ * Whether to skip verification in development/test environments
15
+ * Default: false
16
+ */
17
+ skipInDevelopment?: boolean;
18
+ /**
19
+ * Custom error message when verification fails
20
+ */
21
+ errorMessage?: string;
22
+ /**
23
+ * Logger function for errors
24
+ */
25
+ logger?: {
26
+ warn: (msg: object) => void;
27
+ error: (msg: object) => void;
28
+ };
29
+ }
30
+ /**
31
+ * Creates a middleware that verifies Cloudflare Turnstile tokens
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const verifyTurnstile = createTurnstileMiddleware({
36
+ * secretKey: process.env.TURNSTILE_SECRET_KEY!,
37
+ * skipInDevelopment: process.env.NODE_ENV !== 'production',
38
+ * });
39
+ *
40
+ * app.post('/api/auth/send-code', verifyTurnstile, sendCodeHandler);
41
+ * ```
42
+ */
43
+ export declare function createTurnstileMiddleware(config: TurnstileConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
44
+ export { TurnstileConfig };
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createTurnstileMiddleware = void 0;
16
+ const axios_1 = __importDefault(require("axios"));
17
+ const TURNSTILE_VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
18
+ /**
19
+ * Normalize IP address (handle IPv4-mapped IPv6)
20
+ */
21
+ function normalizeIp(ip) {
22
+ if (!ip)
23
+ return undefined;
24
+ if (ip.startsWith("::ffff:")) {
25
+ return ip.substring(7);
26
+ }
27
+ return ip;
28
+ }
29
+ /**
30
+ * Get client IP from request, prioritizing Cloudflare headers
31
+ */
32
+ function getClientIp(req) {
33
+ const cfConnectingIp = req.headers["cf-connecting-ip"];
34
+ const xForwardedFor = req.headers["x-forwarded-for"];
35
+ if (cfConnectingIp) {
36
+ return normalizeIp(cfConnectingIp);
37
+ }
38
+ if (xForwardedFor) {
39
+ return normalizeIp(xForwardedFor.split(",")[0].trim());
40
+ }
41
+ return normalizeIp(req.ip);
42
+ }
43
+ /**
44
+ * Creates a middleware that verifies Cloudflare Turnstile tokens
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const verifyTurnstile = createTurnstileMiddleware({
49
+ * secretKey: process.env.TURNSTILE_SECRET_KEY!,
50
+ * skipInDevelopment: process.env.NODE_ENV !== 'production',
51
+ * });
52
+ *
53
+ * app.post('/api/auth/send-code', verifyTurnstile, sendCodeHandler);
54
+ * ```
55
+ */
56
+ function createTurnstileMiddleware(config) {
57
+ const { secretKey, tokenField = "turnstileToken", skipInDevelopment = false, errorMessage = "Human verification failed. Please try again.", logger, } = config;
58
+ if (!secretKey) {
59
+ throw new Error("[Turnstile] Secret key is required. Get it from https://dash.cloudflare.com/?to=/:account/turnstile");
60
+ }
61
+ return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
62
+ var _a;
63
+ // Skip in development if configured
64
+ if (skipInDevelopment) {
65
+ return next();
66
+ }
67
+ const token = (_a = req.body) === null || _a === void 0 ? void 0 : _a[tokenField];
68
+ if (!token) {
69
+ logger === null || logger === void 0 ? void 0 : logger.warn({
70
+ message: "Turnstile token missing from request",
71
+ path: req.path,
72
+ ip: getClientIp(req),
73
+ });
74
+ res.status(400).json({
75
+ error: "Verification token is required.",
76
+ });
77
+ return;
78
+ }
79
+ try {
80
+ const remoteIp = getClientIp(req);
81
+ const response = yield axios_1.default.post(TURNSTILE_VERIFY_URL, new URLSearchParams(Object.assign({ secret: secretKey, response: token }, (remoteIp && { remoteip: remoteIp }))), {
82
+ headers: {
83
+ "Content-Type": "application/x-www-form-urlencoded",
84
+ },
85
+ timeout: 10000, // 10 second timeout
86
+ });
87
+ if (response.data.success) {
88
+ // Verification successful
89
+ return next();
90
+ }
91
+ // Verification failed
92
+ logger === null || logger === void 0 ? void 0 : logger.warn({
93
+ message: "Turnstile verification failed",
94
+ path: req.path,
95
+ ip: remoteIp,
96
+ errorCodes: response.data["error-codes"],
97
+ });
98
+ res.status(403).json({
99
+ error: errorMessage,
100
+ codes: response.data["error-codes"],
101
+ });
102
+ }
103
+ catch (error) {
104
+ logger === null || logger === void 0 ? void 0 : logger.error({
105
+ message: "Error verifying Turnstile token",
106
+ path: req.path,
107
+ ip: getClientIp(req),
108
+ error: error instanceof Error ? error.message : String(error),
109
+ });
110
+ // On error, we could either:
111
+ // 1. Block the request (more secure)
112
+ // 2. Allow it through (better UX but less secure)
113
+ // Here we block to be safe
114
+ res.status(500).json({
115
+ error: "Verification service unavailable. Please try again.",
116
+ });
117
+ }
118
+ });
119
+ }
120
+ exports.createTurnstileMiddleware = createTurnstileMiddleware;
@@ -0,0 +1,23 @@
1
+ import mongoose from "mongoose";
2
+ interface ComplianceChatHistoryAttrs {
3
+ sessionId: string;
4
+ sequenceNumber: number;
5
+ createdAt: Date;
6
+ text: string;
7
+ isBot: boolean;
8
+ blobId: number;
9
+ }
10
+ interface ComplianceChatHistoryDoc extends mongoose.Document {
11
+ id: string;
12
+ sessionId: string;
13
+ sequenceNumber: number;
14
+ createdAt: Date;
15
+ text: string;
16
+ isBot: boolean;
17
+ blobId: number;
18
+ }
19
+ interface ComplianceChatHistoryModel extends mongoose.Model<ComplianceChatHistoryDoc> {
20
+ build(attrs: ComplianceChatHistoryAttrs): ComplianceChatHistoryDoc;
21
+ }
22
+ declare const buildComplianceChatHistory: (mongoose: typeof mongoose) => ComplianceChatHistoryModel;
23
+ export { buildComplianceChatHistory, ComplianceChatHistoryDoc, ComplianceChatHistoryAttrs };
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildComplianceChatHistory = void 0;
4
+ const buildComplianceChatHistory = (mongoose) => {
5
+ if (mongoose.models.ComplianceChatHistory) {
6
+ return mongoose.model("ComplianceChatHistory");
7
+ }
8
+ const ComplianceChatHistorySchema = new mongoose.Schema({
9
+ sessionId: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ sequenceNumber: {
14
+ type: Number,
15
+ required: true,
16
+ },
17
+ createdAt: {
18
+ type: Date,
19
+ required: true,
20
+ },
21
+ text: {
22
+ type: String,
23
+ required: true,
24
+ },
25
+ isBot: {
26
+ type: Boolean,
27
+ required: true,
28
+ },
29
+ blobId: {
30
+ type: Number,
31
+ required: true,
32
+ },
33
+ }, {
34
+ collection: 'compliancechathistory',
35
+ toJSON: {
36
+ transform(doc, ret) {
37
+ ret.id = ret._id;
38
+ delete ret._id;
39
+ delete ret.__v;
40
+ },
41
+ },
42
+ });
43
+ ComplianceChatHistorySchema.index({ sessionId: 1, sequenceNumber: 1 });
44
+ ComplianceChatHistorySchema.statics.build = (attrs) => {
45
+ return new ComplianceChatHistory(attrs);
46
+ };
47
+ const ComplianceChatHistory = mongoose.model("ComplianceChatHistory", ComplianceChatHistorySchema);
48
+ return ComplianceChatHistory;
49
+ };
50
+ exports.buildComplianceChatHistory = buildComplianceChatHistory;
@@ -0,0 +1,28 @@
1
+ import mongoose from "mongoose";
2
+ import { ComplianceRuleResultStatus, ComplianceRuleOutcome } from "@riocrypto/common";
3
+ interface ComplianceRuleResultAttrs {
4
+ sessionId: string;
5
+ ruleId: string;
6
+ name: string;
7
+ status: ComplianceRuleResultStatus;
8
+ prompt: string;
9
+ data: string;
10
+ details: string;
11
+ outcome?: ComplianceRuleOutcome;
12
+ }
13
+ interface ComplianceRuleResultDoc extends mongoose.Document {
14
+ id: string;
15
+ sessionId: string;
16
+ ruleId: string;
17
+ name: string;
18
+ status: ComplianceRuleResultStatus;
19
+ prompt: string;
20
+ data: string;
21
+ details: string;
22
+ outcome?: ComplianceRuleOutcome;
23
+ }
24
+ interface ComplianceRuleResultModel extends mongoose.Model<ComplianceRuleResultDoc> {
25
+ build(attrs: ComplianceRuleResultAttrs): ComplianceRuleResultDoc;
26
+ }
27
+ declare const buildComplianceRuleResult: (mongoose: typeof mongoose) => ComplianceRuleResultModel;
28
+ export { buildComplianceRuleResult, ComplianceRuleResultDoc, ComplianceRuleResultAttrs };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildComplianceRuleResult = void 0;
4
+ const buildComplianceRuleResult = (mongoose) => {
5
+ if (mongoose.models.ComplianceRuleResult) {
6
+ return mongoose.model("ComplianceRuleResult");
7
+ }
8
+ const ComplianceRuleResultSchema = new mongoose.Schema({
9
+ sessionId: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ ruleId: {
14
+ type: String,
15
+ required: true,
16
+ },
17
+ name: {
18
+ type: String,
19
+ required: true,
20
+ },
21
+ status: {
22
+ type: String,
23
+ required: true,
24
+ },
25
+ prompt: {
26
+ type: String,
27
+ required: true,
28
+ },
29
+ data: {
30
+ type: String,
31
+ required: false,
32
+ },
33
+ details: {
34
+ type: String,
35
+ required: false,
36
+ },
37
+ outcome: {
38
+ type: String,
39
+ required: false,
40
+ },
41
+ }, {
42
+ toJSON: {
43
+ transform(doc, ret) {
44
+ ret.id = ret._id;
45
+ delete ret._id;
46
+ delete ret.__v;
47
+ },
48
+ },
49
+ });
50
+ ComplianceRuleResultSchema.index({ sessionId: 1 });
51
+ ComplianceRuleResultSchema.statics.build = (attrs) => {
52
+ return new ComplianceRuleResult(attrs);
53
+ };
54
+ const ComplianceRuleResult = mongoose.model("ComplianceRuleResult", ComplianceRuleResultSchema);
55
+ return ComplianceRuleResult;
56
+ };
57
+ exports.buildComplianceRuleResult = buildComplianceRuleResult;
@@ -0,0 +1,19 @@
1
+ import mongoose from "mongoose";
2
+ interface ComplianceRuleAttrs {
3
+ country: string;
4
+ name: string;
5
+ prompt: string;
6
+ ruleType: string;
7
+ }
8
+ interface ComplianceRuleDoc extends mongoose.Document {
9
+ id: string;
10
+ country: string;
11
+ name: string;
12
+ prompt: string;
13
+ ruleType: string;
14
+ }
15
+ interface ComplianceRuleModel extends mongoose.Model<ComplianceRuleDoc> {
16
+ build(attrs: ComplianceRuleAttrs): ComplianceRuleDoc;
17
+ }
18
+ declare const buildComplianceRule: (mongoose: typeof mongoose) => ComplianceRuleModel;
19
+ export { buildComplianceRule, ComplianceRuleDoc, ComplianceRuleAttrs };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildComplianceRule = void 0;
4
+ const buildComplianceRule = (mongoose) => {
5
+ if (mongoose.models.ComplianceRule) {
6
+ return mongoose.model("ComplianceRule");
7
+ }
8
+ const ComplianceRuleSchema = new mongoose.Schema({
9
+ country: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ name: {
14
+ type: String,
15
+ required: true,
16
+ },
17
+ prompt: {
18
+ type: String,
19
+ required: true,
20
+ },
21
+ ruleType: {
22
+ type: String,
23
+ required: true,
24
+ },
25
+ }, {
26
+ toJSON: {
27
+ transform(doc, ret) {
28
+ ret.id = ret._id;
29
+ delete ret._id;
30
+ delete ret.__v;
31
+ },
32
+ },
33
+ });
34
+ ComplianceRuleSchema.index({ country: 1 });
35
+ ComplianceRuleSchema.statics.build = (attrs) => {
36
+ return new ComplianceRule(attrs);
37
+ };
38
+ const ComplianceRule = mongoose.model("ComplianceRule", ComplianceRuleSchema);
39
+ return ComplianceRule;
40
+ };
41
+ exports.buildComplianceRule = buildComplianceRule;
@@ -0,0 +1,27 @@
1
+ import mongoose from "mongoose";
2
+ import { ComplianceSessionStatus } from "@riocrypto/common";
3
+ interface ComplianceSessionAttrs {
4
+ id: string;
5
+ userId: string;
6
+ createdAt: Date;
7
+ country: string;
8
+ message: string;
9
+ status: ComplianceSessionStatus;
10
+ transcript: string;
11
+ modelName: string;
12
+ }
13
+ interface ComplianceSessionDoc extends mongoose.Document {
14
+ id: string;
15
+ userId: string;
16
+ createdAt: Date;
17
+ country: string;
18
+ message: string;
19
+ status: ComplianceSessionStatus;
20
+ transcript: string;
21
+ modelName: string;
22
+ }
23
+ interface ComplianceSessionModel extends mongoose.Model<ComplianceSessionDoc> {
24
+ build(attrs: ComplianceSessionAttrs): ComplianceSessionDoc;
25
+ }
26
+ declare const buildComplianceSession: (mongoose: typeof mongoose) => ComplianceSessionModel;
27
+ export { buildComplianceSession, ComplianceSessionDoc, ComplianceSessionAttrs };
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildComplianceSession = void 0;
4
+ const buildComplianceSession = (mongoose) => {
5
+ if (mongoose.models.ComplianceSession) {
6
+ return mongoose.model("ComplianceSession");
7
+ }
8
+ const ComplianceSessionSchema = new mongoose.Schema({
9
+ userId: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ createdAt: {
14
+ type: Date,
15
+ required: true,
16
+ },
17
+ country: {
18
+ type: String,
19
+ required: false,
20
+ },
21
+ message: {
22
+ type: String,
23
+ required: false,
24
+ default: "",
25
+ },
26
+ status: {
27
+ type: String,
28
+ required: false,
29
+ default: "",
30
+ },
31
+ transcript: {
32
+ type: String,
33
+ required: false,
34
+ default: "",
35
+ },
36
+ modelName: {
37
+ type: String,
38
+ required: false,
39
+ },
40
+ }, {
41
+ toJSON: {
42
+ transform(doc, ret) {
43
+ ret.id = ret._id;
44
+ delete ret._id;
45
+ delete ret.__v;
46
+ },
47
+ },
48
+ });
49
+ ComplianceSessionSchema.index({ id: 1 });
50
+ ComplianceSessionSchema.index({ userId: 1 });
51
+ ComplianceSessionSchema.index({ createdAt: 1 });
52
+ ComplianceSessionSchema.statics.build = (attrs) => {
53
+ return new ComplianceSession(attrs);
54
+ };
55
+ const ComplianceSession = mongoose.model("ComplianceSession", ComplianceSessionSchema);
56
+ return ComplianceSession;
57
+ };
58
+ exports.buildComplianceSession = buildComplianceSession;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2695",
3
+ "version": "1.0.2698",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "@google-cloud/secret-manager": "^5.3.0",
29
29
  "@google-cloud/storage": "^6.9.5",
30
30
  "@hyperdx/node-opentelemetry": "^0.7.0",
31
- "@riocrypto/common": "^1.0.2493",
31
+ "@riocrypto/common": "^1.0.2496",
32
32
  "@types/express": "^4.17.13",
33
33
  "axios": "^1.7.4",
34
34
  "crypto-js": "^4.2.0",