UNPKG

@aikidosec/firewall

Version:

Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks

204 lines (203 loc) 7.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ServiceConfig = void 0; const IPMatcher_1 = require("../helpers/ip-matcher/IPMatcher"); const matchEndpoints_1 = require("../helpers/matchEndpoints"); const isPrivateIP_1 = require("../vulnerabilities/ssrf/isPrivateIP"); const safeCreateRegExp_1 = require("./safeCreateRegExp"); class ServiceConfig { constructor(endpoints, lastUpdatedAt, blockedUserIds, bypassedIPAddresses, receivedAnyStats, blockedIPAddresses, allowedIPAddresses) { this.lastUpdatedAt = lastUpdatedAt; this.receivedAnyStats = receivedAnyStats; this.blockedUserIds = new Map(); this.nonGraphQLEndpoints = []; this.graphqlFields = []; this.blockedIPAddresses = []; // If not empty, only ips in this list are allowed to access the service // e.g. for country allowlists this.allowedIPAddresses = []; this.monitoredIPAddresses = []; this.userAgentDetails = []; this.setBlockedUserIds(blockedUserIds); this.setBypassedIPAddresses(bypassedIPAddresses); this.setEndpoints(endpoints); this.setBlockedIPAddresses(blockedIPAddresses); this.setAllowedIPAddresses(allowedIPAddresses); } setEndpoints(endpointConfigs) { this.nonGraphQLEndpoints = []; this.graphqlFields = []; for (const endpoint of endpointConfigs) { let allowedIPAddresses = undefined; if (Array.isArray(endpoint.allowedIPAddresses) && endpoint.allowedIPAddresses.length > 0) { allowedIPAddresses = new IPMatcher_1.IPMatcher(endpoint.allowedIPAddresses); } const endpointConfig = { ...endpoint, allowedIPAddresses }; if (endpoint.graphql) { this.graphqlFields.push(endpointConfig); } else { this.nonGraphQLEndpoints.push(endpointConfig); } } } getEndpoints(context) { return (0, matchEndpoints_1.matchEndpoints)(context, this.nonGraphQLEndpoints); } getGraphQLField(context, name, operationType) { const endpoints = (0, matchEndpoints_1.matchEndpoints)(context, this.graphqlFields.filter((field) => { if (!field.graphql) { return false; } return (field.graphql.name === name && field.graphql.type === operationType); })); return endpoints.length > 0 ? endpoints[0] : undefined; } setBypassedIPAddresses(ipAddresses) { if (ipAddresses.length === 0) { this.bypassedIPAddresses = undefined; return; } this.bypassedIPAddresses = new IPMatcher_1.IPMatcher(ipAddresses); } isBypassedIP(ip) { return this.bypassedIPAddresses ? this.bypassedIPAddresses.has(ip) : false; } setBlockedUserIds(blockedUserIds) { this.blockedUserIds = new Map(); blockedUserIds.forEach((userId) => { this.blockedUserIds.set(userId, userId); }); } isUserBlocked(userId) { return this.blockedUserIds.has(userId); } isIPAddressBlocked(ip) { const blocklist = this.blockedIPAddresses.find((blocklist) => blocklist.blocklist.has(ip)); if (blocklist) { return { blocked: true, reason: blocklist.description }; } return { blocked: false }; } setBlockedIPAddresses(blockedIPAddresses) { this.blockedIPAddresses = []; for (const source of blockedIPAddresses) { this.blockedIPAddresses.push({ key: source.key, blocklist: new IPMatcher_1.IPMatcher(source.ips), description: source.description, }); } } updateBlockedIPAddresses(blockedIPAddresses) { this.setBlockedIPAddresses(blockedIPAddresses); } updateMonitoredIPAddresses(monitoredIPAddresses) { this.monitoredIPAddresses = []; for (const source of monitoredIPAddresses) { this.monitoredIPAddresses.push({ key: source.key, list: new IPMatcher_1.IPMatcher(source.ips), }); } } updateBlockedUserAgents(blockedUserAgents) { if (!blockedUserAgents) { // If an empty string is passed, we want to set the regex to undefined // e.g. new RegExp("").test("abc") == true this.blockedUserAgentRegex = undefined; return; } this.blockedUserAgentRegex = (0, safeCreateRegExp_1.safeCreateRegExp)(blockedUserAgents, "i"); } isUserAgentBlocked(ua) { if (this.blockedUserAgentRegex) { return { blocked: this.blockedUserAgentRegex.test(ua) }; } return { blocked: false }; } updateUserAgentDetails(userAgentDetails) { this.userAgentDetails = []; for (const detail of userAgentDetails) { const regex = (0, safeCreateRegExp_1.safeCreateRegExp)(detail.pattern, "i"); if (regex) { this.userAgentDetails.push({ key: detail.key, pattern: regex, }); } } } updateMonitoredUserAgents(monitoredUserAgent) { if (!monitoredUserAgent) { // If an empty string is passed, we want to set the regex to undefined // e.g. new RegExp("").test("abc") == true this.monitoredUserAgentRegex = undefined; return; } this.monitoredUserAgentRegex = (0, safeCreateRegExp_1.safeCreateRegExp)(monitoredUserAgent, "i"); } isMonitoredUserAgent(ua) { if (this.monitoredUserAgentRegex) { return this.monitoredUserAgentRegex.test(ua); } return false; } getMatchingUserAgentKeys(ua) { return this.userAgentDetails .filter((details) => details.pattern.test(ua)) .map((details) => details.key); } getMatchingBlockedIPListKeys(ip) { return this.blockedIPAddresses .filter((list) => list.blocklist.has(ip)) .map((list) => list.key); } getMatchingMonitoredIPListKeys(ip) { return this.monitoredIPAddresses .filter((list) => list.list.has(ip)) .map((list) => list.key); } setAllowedIPAddresses(ipAddresses) { this.allowedIPAddresses = []; for (const source of ipAddresses) { // Skip empty allowlists if (source.ips.length === 0) { continue; } this.allowedIPAddresses.push({ allowlist: new IPMatcher_1.IPMatcher(source.ips), description: source.description, }); } } updateAllowedIPAddresses(ipAddresses) { this.setAllowedIPAddresses(ipAddresses); } isAllowedIPAddress(ip) { if (this.allowedIPAddresses.length < 1) { return { allowed: true }; } // Always allow access from local IP addresses if ((0, isPrivateIP_1.isPrivateIP)(ip)) { return { allowed: true }; } const allowlist = this.allowedIPAddresses.find((list) => list.allowlist.has(ip)); return { allowed: !!allowlist }; } updateConfig(endpoints, lastUpdatedAt, blockedUserIds, bypassedIPAddresses, hasReceivedAnyStats) { this.setEndpoints(endpoints); this.setBlockedUserIds(blockedUserIds); this.setBypassedIPAddresses(bypassedIPAddresses); this.lastUpdatedAt = lastUpdatedAt; this.receivedAnyStats = hasReceivedAnyStats; } getLastUpdatedAt() { return this.lastUpdatedAt; } hasReceivedAnyStats() { return this.receivedAnyStats; } } exports.ServiceConfig = ServiceConfig;