diff --git a/.gitignore b/.gitignore index 5b38519..6fb16ff 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,8 @@ key/ *.history .histoy *.vscode -.vscode \ No newline at end of file +.vscode + +#Other +legacy_wrapper.js +.DS_Store \ No newline at end of file diff --git a/client/block.hbs b/client/block.hbs index a7c8174..c49bc4e 100644 --- a/client/block.hbs +++ b/client/block.hbs @@ -316,136 +316,242 @@ {{#if details.indicators}}
- {{#each details.indicators as |object index|}} - {{#if (gt index 0)}} -
- {{/if}} -
- View IOC in Flashpoint {{fa-icon "external-link-square" class="external-link-icon"}} -
- {{#each-in object.Attribute.value as | key value |}} - {{#if value}} -
- {{key}}: - {{value}} -
- {{/if}} - {{/each-in}} + {{#each details.indicators as |indicator index|}} +
+
+
{{indicator.value}}
+ {{#if indicator.platform_urls.ignite}} + + {{/if}} - {{#if object.Attribute.category}} -
- Category: - {{object.Attribute.category}} -
- {{/if}} + {{#if indicator.score.value}} +
+ Score: + {{indicator.score.value}} +
+ {{/if}} - {{#if object.Attribute.timestamp}} -
- Indicator Timestamp: - {{moment-format - (unix object.Attribute.timestamp) - "YYYY-MM-DD HH:mm:ss z" - timeZone=timezone - }} -
- {{/if}} + {{#if indicator.modified_at}} +
+ Modified at: + + {{moment-format indicator.modified_at "YYYY-MM-DD HH:mm:ss z" timeZone=timezone}} + +
+ {{/if}} - {{#if (gt object.Attribute.Event.Tags.length 0)}} -

{{fa-icon icon="tags" fixedWidth=true}} Event Tags

-
- {{#each object.Attribute.Event.Tags as | tag |}} - {{tag}} - {{/each}} -
- {{/if}} + {{#if indicator.created_at}} +
+ Created at: + + {{moment-format indicator.created_at "YYYY-MM-DD HH:mm:ss z" timeZone=timezone}} + +
+ {{/if}} - {{#if object.Attribute.Event.href}} -
-
- {{object.Attribute.Event.info}} -
-
- {{#if object._eventLoading}} - {{fa-icon icon="spinner-third" spin=true fixedWidth=true}} - {{else if object._eventOpen}} - {{fa-icon icon="chevron-up" fixedWidth=true}} - {{else}} - {{fa-icon icon="chevron-down" fixedWidth=true}} - {{/if}} -
-
- {{#if object._eventLoading}} -
- Loading event details ... -
- {{/if}} - {{/if}} + {{#if indicator.last_seen_at}} +
+ Last seen at: + + {{moment-format indicator.last_seen_at "YYYY-MM-DD HH:mm:ss z" timeZone=timezone}} + +
+ {{/if}} - {{#if object._eventEnrichedError}} -
-
-
{{fa-icon icon="exclamation-triangle" fixedWidth=true}} Error Fetching Event Data
- {{fa-icon icon="times" fixedWidth=true class="error-close" click=(action "clearError" index)}} -
-
{{object._eventEnrichedError}}
-
- {{/if}} + {{#if indicator.total_sightings}} +
+ Total Sightings: + {{indicator.total_sightings}} +
+ {{/if}} - {{#if (and object._eventEnriched object._eventOpen)}} -
- {{#if object._eventEnriched.malware_description}} -
-
- {{{object._eventEnriched.malware_description}}} -
+ {{#if indicator.latest_sighting.source}} +
+ Source: + {{indicator.latest_sighting.source}}
- {{#each object._eventEnriched.Event.Attribute as | attribute |}} + {{/if}} + {{#if indicator.latest_sighting.description}} +
+ Description: + {{indicator.latest_sighting.description}} +
+ {{/if}} + + {{#if (gt indicator.latest_sighting.tags.length 0)}} +

{{fa-icon icon="tags" fixedWidth=true}} Recent Tags

+
+ {{#each indicator.latest_sighting.tags as |tag|}} + {{tag}} + {{/each}} +
+ {{/if}} + + {{#if (gt indicator._indicatorDetails._extractedConfigs.length 0)}} +

Extracted Configuration

+ {{#each indicator._indicatorDetails._extractedConfigs as |config|}}
-
- {{attribute.category}} - attribute -
- {{#each-in attribute.value as | key value |}} - {{#if value}} -
- {{key}}: - {{value}} -
- {{/if}} - {{/each-in}} - {{#if attribute.timestamp}} -
- Time: - - {{moment-format - (unix attribute.timestamp) - "YYYY-MM-DD HH:mm:ss z" - timeZone=timezone - }} - -
- {{/if}} - {{#if attribute.last_seen}} -
- Last Seen: - - {{moment-format - (unix attribute.last_seen) - "YYYY-MM-DD HH:mm:ss z" - timeZone=timezone - }} - -
+ {{#if config.value}} +
{{config.value}}
{{/if}}
{{/each}} {{/if}} -
- {{/if}} + {{#if (or (not indicator._indicatorDetailsOpen) indicator._indicatorDetailsLoading)}} +
+ + View Sighting, Related IOCs, and Mitre ATT&CK + {{fa-icon icon="sync" fixedWidth=true spin=indicator._indicatorDetailsLoading}} + +
+ {{/if}} + + {{#if indicator._indicatorDetailsOpen}} + {{#if indicator._indicatorDetailsError}} +
+
+ {{fa-icon icon="exclamation-triangle" fixedWidth=true}} + Error Fetching Indicator Details +
+
{{indicator._indicatorDetailsError}}
+
+ {{/if}} + {{#if indicator._indicatorDetailsLoaded}} +
+ + {{#if indicator._showRelatedIocs}} + Hide + {{else}} + Show + {{/if}} + Related IOCs + {{fa-icon (if indicator._showRelatedIocs "caret-up" "caret-down") fixedWidth=true}} + +
+ {{#if indicator._showRelatedIocs}} + {{#if (gt indicator._indicatorDetails._relatedIocs.length 0)}} +
+
+ + + + + + + + + {{#each indicator._indicatorDetails._relatedIocs as |ioc|}} + + + + + {{/each}} + + +
+
+ {{else}} +
No related IOCs.
+ {{/if}} + {{/if}} + +
+ + {{#if indicator._showSightings}} + Hide + {{else}} + Show + {{/if}} + Sightings + {{fa-icon (if indicator._showSightings "caret-up" "caret-down") fixedWidth=true}} + +
+ {{#if indicator._showSightings}} + {{#if (gt indicator._indicatorDetails.sightings.length 0)}} + {{#each indicator._indicatorDetails.sightings as |sighting|}} +
+
+ {{#if sighting.source}} +
+ Source: + {{sighting.source}} +
+ {{/if}} + {{#if sighting.sighted_at}} +
+ Sighted At: + + {{moment-format sighting.sighted_at "YYYY-MM-DD HH:mm:ss z" timeZone=timezone}} + +
+ {{/if}} + {{#if sighting.description}} +
+ Description: + {{sighting.description}} +
+ {{/if}} +
+
+ {{/each}} + {{else}} +
No sightings.
+ {{/if}} + {{/if}} + +
+ + {{#if indicator._showMitre}} + Hide + {{else}} + Show + {{/if}} + Mitre ATT&CK + {{fa-icon (if indicator._showMitre "caret-up" "caret-down") fixedWidth=true}} + +
+ {{#if indicator._showMitre}} + {{#if (gt indicator._indicatorDetails._mitreByTactic.length 0)}} + {{#each indicator._indicatorDetails._mitreByTactic as |group groupIndex|}} +
+
+
+ {{group.tactic}}: {{group.techniques.length}} +
+
+ {{#if group._open}} + {{fa-icon icon="chevron-up" fixedWidth=true}} + {{else}} + {{fa-icon icon="chevron-down" fixedWidth=true}} + {{/if}} +
+
+ {{#if group._open}} +
+ {{#each group.techniques as |technique|}} + {{technique.name}} ({{technique.id}}) + {{/each}} +
+ {{/if}} +
+ {{/each}} + {{else}} +
No MITRE ATT&CK data.
+ {{/if}} + {{/if}} + {{/if}} + {{/if}} +
+
{{/each}}
{{/if}} diff --git a/client/block.js b/client/block.js index 6ade188..b8bf6e8 100644 --- a/client/block.js +++ b/client/block.js @@ -94,6 +94,54 @@ polarity.export = PolarityComponent.extend({ }); } }, + toggleIndicatorDetails: function (indicator, index) { + const indicatorPath = `details.indicators.${index}`; + + if (this.get(`${indicatorPath}._indicatorDetailsLoaded`)) { + this.toggleProperty(`${indicatorPath}._indicatorDetailsOpen`); + return; + } + + this.set(`${indicatorPath}._indicatorDetailsLoading`, true); + + const payload = { + action: 'GET_INDICATOR_DETAILS', + indicatorId: indicator.id, + }; + + this.sendIntegrationMessage(payload) + .then((result) => { + const groupedMitre = this.groupMitreByTactic(result.mitre_attack_ids || []); + const relatedIocs = this.collectRelatedIocs(result.sightings || []); + const splitIocs = this.splitExtractedConfigs(relatedIocs); + + result._mitreByTactic = groupedMitre; + result._relatedIocs = splitIocs.relatedIocs; + result._extractedConfigs = splitIocs.extractedConfigs; + + this.set(`${indicatorPath}._indicatorDetails`, result); + this.set(`${indicatorPath}._indicatorDetailsLoaded`, true); + this.set(`${indicatorPath}._indicatorDetailsOpen`, true); + }) + .catch((error) => { + console.error('Error fetching indicator details', error); + this.set( + `${indicatorPath}._indicatorDetailsError`, + JSON.stringify(error, null, 2) + ); + }) + .finally(() => { + this.set(`${indicatorPath}._indicatorDetailsLoading`, false); + }); + }, + toggleMitreGroup: function (indicatorIndex, groupIndex) { + const groupPath = `details.indicators.${indicatorIndex}._indicatorDetails._mitreByTactic.${groupIndex}._open`; + this.toggleProperty(groupPath); + }, + toggleIndicatorSection: function (indicatorIndex, sectionKey) { + const sectionPath = `details.indicators.${indicatorIndex}._${sectionKey}`; + this.toggleProperty(sectionPath); + }, copyData: function () { Ember.run.scheduleOnce( 'afterRender', @@ -124,5 +172,72 @@ polarity.export = PolarityComponent.extend({ this.set('showCopyMessage', false); } }, 2000); + }, + groupMitreByTactic(mitreAttackIds) { + const groupsByTactic = {}; + + mitreAttackIds.forEach((attack) => { + const tactic = attack.tactic || 'Unknown'; + + if (!groupsByTactic[tactic]) { + groupsByTactic[tactic] = { + tactic, + techniques: [], + _techniqueKeys: new Set(), + _open: false + }; + } + + const key = `${attack.name || ''}::${attack.id || ''}`; + + if (!groupsByTactic[tactic]._techniqueKeys.has(key)) { + groupsByTactic[tactic]._techniqueKeys.add(key); + groupsByTactic[tactic].techniques.push({ + id: attack.id, + name: attack.name + }); + } + }); + + return Object.values(groupsByTactic) + .map((group) => { + delete group._techniqueKeys; + group.techniques.sort((a, b) => + (a.name || '').localeCompare(b.name || '', 'en', { sensitivity: 'base' }) + ); + return group; + }) + .sort((a, b) => + (a.tactic || '').localeCompare(b.tactic || '', 'en', { sensitivity: 'base' }) + ); + }, + collectRelatedIocs(sightings) { + const byKey = new Map(); + + sightings.forEach((sighting) => { + (sighting.related_iocs || []).forEach((ioc) => { + const key = ioc.id || ioc.href || `${ioc.type || ''}:${ioc.value || ''}`; + + if (!byKey.has(key)) { + byKey.set(key, ioc); + } + }); + }); + + return Array.from(byKey.values()); + }, + splitExtractedConfigs(iocs) { + const extractedConfigs = []; + const relatedIocs = []; + + iocs.forEach((ioc) => { + if (ioc.type === 'extracted_config') { + extractedConfigs.push(ioc); + } else { + relatedIocs.push(ioc); + } + }); + + return { relatedIocs, extractedConfigs }; } }); diff --git a/client/styles.less b/client/styles.less index c15e5c1..132181d 100644 --- a/client/styles.less +++ b/client/styles.less @@ -303,3 +303,20 @@ pre { } } } + +.related-iocs-table { + width: 100%; + + .type-col { + min-width: 120px; + } +} + +.indicator-title { + font-weight: bold; + font-size: 1.1em; +} + +.toggle-header { + margin-bottom: 6px; +} diff --git a/config/config.js b/config/config.js deleted file mode 100644 index 4b2b7c7..0000000 --- a/config/config.js +++ /dev/null @@ -1,132 +0,0 @@ -module.exports = { - name: 'Flashpoint', - acronym: 'FP', - description: - 'Flashpoint delivers Business Risk Intelligence (BRI) that empowers organizations worldwide to combat threats and adversaries', - entityTypes: ['IPv4', 'MD5', 'SHA1', 'SHA256', 'domain', 'email', 'cve'], - styles: ['./client/styles.less'], - defaultColor: 'light-blue', - block: { - component: { - file: './client/block.js' - }, - template: { - file: './client/block.hbs' - } - }, - request: { - cert: '', - key: '', - passphrase: '', - ca: '', - proxy: '' - }, - logging: { - level: 'info' - }, - options: [ - { - key: 'url', - name: 'Flashpoint API URL', - description: - 'The base URL of the Flashpoint API including the schema (i.e., https://)', - default: 'https://api.flashpoint.io', - type: 'text', - userCanEdit: false, - adminOnly: true - }, - { - key: 'apiKey', - name: 'API Key', - description: 'Valid Flashpoint Ignite API Key', - default: '', - type: 'password', - userCanEdit: true, - adminOnly: false - }, - { - key: 'limit', - name: 'Result Limit', - description: 'The maximum amount of results to be returned per query', - default: 10, - type: 'number', - userCanEdit: true, - adminOnly: false - }, - { - key: 'indicatorSearchWindow', - name: 'Indicator Search Window', - description: 'How far back from now to search for indicators (defaults to 30 days)', - default: { - value: '30d', - display: '1 month' - }, - type: 'select', - options: [ - { - value: '0', - display: 'All time' - }, - { - value: '5y', - display: '5 years' - }, - { - value: '3y', - display: '3 years' - }, - { - value: '1y', - display: '1 year' - }, - { - value: '6M', - display: '6 months' - }, - { - value: '3M', - display: '3 months' - }, - { - value: '30d', - display: '1 month' - }, - { - value: '7d', - display: '1 week' - } - ], - multiple: false, - userCanEdit: false, - adminOnly: true - }, - { - key: 'blocklist', - name: 'Ignore List', - description: - 'Comma delimited List of domains and IPs that you never want to send to Flashpoint', - default: '', - type: 'text', - userCanEdit: false, - adminOnly: false - }, - { - key: 'domainBlocklistRegex', - name: 'Ignore Domain Regex', - description: 'Domains that match the given regex will not be looked up.', - default: '', - type: 'text', - userCanEdit: false, - adminOnly: false - }, - { - key: 'ipBlocklistRegex', - name: 'Ignore IP Regex', - description: 'IPs that match the given regex will not be looked up.', - default: '', - type: 'text', - userCanEdit: false, - adminOnly: false - } - ] -}; diff --git a/integration.js b/integration.js index 8d60e9e..bbd74a9 100644 --- a/integration.js +++ b/integration.js @@ -10,7 +10,7 @@ const { removePrivateIps, removeEntityTypes, getEntityTypes, - removeBlocklistedIpsAndDomains + removeBlockListedIpsAndDomains } = require('./server/dataTransformations'); const { getReportById, @@ -18,22 +18,31 @@ const { getIndicators, getReports, getVulnerability, - getReportImage + getReportImage, + getIndicatorDetails } = require('./server/queries'); const assembleLookupResults = require('./server/assembleLookupResults'); + +let Logger = null; + +const startup = (logger) => { + Logger = logger; + setLogger(Logger); +}; + const doLookup = async (entities, options, cb) => { const Logger = getLogger(); try { Logger.trace({ entities }, 'doLookup'); - const entitiesWithoutBlocklistedEntities = removeBlocklistedIpsAndDomains( + const entitiesWithoutBlockListedEntities = removeBlockListedIpsAndDomains( entities, options ); - const searchableEntities = removePrivateIps(entitiesWithoutBlocklistedEntities); + const searchableEntities = removePrivateIps(entitiesWithoutBlockListedEntities); const nonCveEntities = removeEntityTypes('cve', searchableEntities); const cveEntities = getEntityTypes('cve', searchableEntities); @@ -115,6 +124,23 @@ const onMessage = async (payload, options, cb) => { cb(err); } break; + case 'GET_INDICATOR_DETAILS': + try { + const indicatorDetails = await getIndicatorDetails( + payload.indicatorId, + options + ); + cb(null, indicatorDetails); + } catch (error) { + const err = parseErrorToReadableJson(error); + + Logger.error( + { error, formattedError: err }, + 'GET_INDICATOR_DETAILS Failed' + ); + cb(err); + } + break; } }; @@ -141,7 +167,7 @@ const onDetails = async (lookupObject, options, cb) => { }; module.exports = { - startup: setLogger, + startup, validateOptions, doLookup, onDetails, diff --git a/package-lock.json b/package-lock.json index c1281d4..ff11670 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,358 +1,434 @@ { "name": "Flashpoint", - "version": "3.4.1", - "lockfileVersion": 1, + "version": "3.5.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@postman/form-data": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", - "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "packages": { + "": { + "name": "Flashpoint", + "version": "3.5.0", + "dependencies": { + "async": "^3.2.6", + "polarity-integration-utils": "^0.1.0" } }, - "@postman/tough-cookie": { - "version": "4.1.3-postman.1", - "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", - "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, - "@postman/tunnel-agent": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.4.tgz", - "integrity": "sha512-CJJlq8V7rNKhAw4sBfjixKpJW00SHqebqNUQKxMoepgeWZIbdPcD+rguRcivGhS4N12PymDcKgUgSD4rVC+RjQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ajv": { + "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "asn1": { + "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { + "license": "MIT", + "dependencies": { "safer-buffer": "~2.1.0" } }, - "assert-plus": { + "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } }, - "async": { + "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, - "asynckit": { + "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, - "aws-sign2": { + "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } }, - "aws4": { + "node_modules/aws4": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bcrypt-pbkdf": { + "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "tweetnacl": "^0.14.3" } }, - "bluebird": { + "node_modules/bluebird": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==" }, - "bottleneck": { + "node_modules/bottleneck": { "version": "2.19.5", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" }, - "brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "requires": { - "base64-js": "^1.1.2" - } - }, - "caseless": { + "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, - "combined-stream": { + "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { + "license": "MIT", + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "core-util-is": { + "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" }, - "dashdash": { + "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" } }, - "delayed-stream": { + "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } }, - "ecc-jsbn": { + "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { + "license": "MIT", + "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, - "extend": { + "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extsprintf": { + "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, - "forever-agent": { + "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } }, - "getpass": { + "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0" } }, - "har-schema": { + "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } }, - "har-validator": { + "node_modules/har-validator": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { + "deprecated": "this library is no longer supported", + "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" } }, - "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "requires": { + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" } }, - "is-typedarray": { + "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, - "isstream": { + "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, - "jsbn": { + "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" }, - "json-schema": { + "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stringify-safe": { + "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, - "jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "requires": { + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "license": "MIT", + "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" }, - "mime-db": { + "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { + "license": "MIT", + "dependencies": { "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "oauth-sign": { + "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } }, - "performance-now": { + "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, - "polarity-integration-utils": { + "node_modules/polarity-integration-utils": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/polarity-integration-utils/-/polarity-integration-utils-0.1.0.tgz", "integrity": "sha512-EcIXLM7Dcfs+UC9i5f491+VT6D29rsuK7JxwE3rTZxbwuyoUOi0dCSqB4fIDMtDt7jdpppGp6l/HVWPh7/NBfg==", - "requires": { + "dependencies": { "bottleneck": "^2.19.5", "lodash": "^4.17.21", "postman-request": "^2.88.1-postman.32" } }, - "postman-request": { - "version": "2.88.1-postman.40", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.40.tgz", - "integrity": "sha512-uE4AiIqhjtHKp4pj9ei7fkdfNXEX9IqDBlK1plGAQne6y79UUlrTdtYLhwXoO0AMOvqyl9Ar+BU6Eo6P/MPgfg==", - "requires": { - "@postman/form-data": "~3.1.1", - "@postman/tough-cookie": "~4.1.3-postman.1", - "@postman/tunnel-agent": "^0.6.4", + "node_modules/postman-request": { + "version": "2.88.1-postman.8-beta.1", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.8-beta.1.tgz", + "integrity": "sha512-deC5UZlM1VimFhQdPN1NcbQMvLEtpUCTHZHMXWNv6vyNW7H98O3MJGTlk2xTlzB9BOpU2MCCgXNOPeNP2SU6iA==", + "license": "Apache-2.0", + "dependencies": { "aws-sign2": "~0.7.0", - "aws4": "^1.12.0", - "brotli": "^1.3.3", + "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", + "form-data": "~2.3.2", "har-validator": "~5.1.3", - "http-signature": "~1.3.1", + "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "^2.1.35", + "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.3", + "postman-url-encoder": "1.0.1", + "qs": "~6.5.2", "safe-buffer": "^5.1.2", "stream-length": "^1.0.2", - "uuid": "^8.3.2" + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" } }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + "node_modules/postman-url-encoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-1.0.1.tgz", + "integrity": "sha512-ned2lpcMpEG+n3ce2LEoGqUJeZsKNRYkViqKfJXe7rUQhLxjrrcp/lQ8TLycvX74lQZm52gkNVVgczmcJBOJ8w==", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } }, - "punycode": { + "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } }, - "qs": { + "node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "sshpk": { + "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "requires": { + "license": "MIT", + "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", @@ -362,53 +438,82 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" } }, - "stream-length": { + "node_modules/stream-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", - "requires": { + "dependencies": { "bluebird": "^2.6.2" } }, - "tweetnacl": { + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" - }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" } }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "verror": { + "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" diff --git a/package.json b/package.json index 569daaa..52b8835 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Flashpoint", - "version": "3.4.1", + "version": "3.5.0", "main": "./integration.js", "private": true, "dependencies": { diff --git a/server/assembleLookupResults.js b/server/assembleLookupResults.js index dbd95b8..1f7f89b 100644 --- a/server/assembleLookupResults.js +++ b/server/assembleLookupResults.js @@ -26,8 +26,8 @@ const assembleLookupResults = (entities, indicators, vulnResults, options) => }, entities); const getResultsForThisEntity = (entity, indicators, vulnResults, options) => ({ - indicators: getResultForThisEntity(entity, indicators), - vulnerabilities: getResultForThisEntity(entity, vulnResults) + indicators: getResultForThisEntity(entity, indicators) || [], + vulnerabilities: getResultForThisEntity(entity, vulnResults) || [] }); const createSummaryTags = ({ indicators, vulnerabilities }, options) => { diff --git a/server/dataTransformations.js b/server/dataTransformations.js index 6a0af75..994807a 100644 --- a/server/dataTransformations.js +++ b/server/dataTransformations.js @@ -92,7 +92,7 @@ const getResultForThisEntity = ( const splitCommaSeparatedUserOption = (key, options) => flow(get(key), split(','), map(trim), compact, uniq)(options); -const removeBlocklistedIpsAndDomains = (entities, options) => { +const removeBlockListedIpsAndDomains = (entities, options) => { const ipBlocklistRegex = setupBlocklistRegex('ipBlocklistRegex', options); const domainBlocklistRegex = setupBlocklistRegex('domainBlocklistRegex', options); @@ -125,5 +125,5 @@ module.exports = { removeEntityTypes, getResultForThisEntity, splitCommaSeparatedUserOption, - removeBlocklistedIpsAndDomains + removeBlockListedIpsAndDomains }; diff --git a/server/queries/getIndicatorDetails.js b/server/queries/getIndicatorDetails.js new file mode 100644 index 0000000..854ca19 --- /dev/null +++ b/server/queries/getIndicatorDetails.js @@ -0,0 +1,33 @@ +const { get } = require('lodash/fp'); +const { + logging: { getLogger }, + errors: { parseErrorToReadableJson } +} = require('polarity-integration-utils'); +const { requestWithDefaults } = require('../request'); + +const getIndicatorDetails = async (indicatorId, options) => { + const Logger = getLogger(); + + try { + const requestOptions = { + route: `technical-intelligence/v2/indicators/${indicatorId}`, + options + }; + const indicatorDetails = get('body', await requestWithDefaults(requestOptions)); + + return indicatorDetails; + } catch (error) { + const err = parseErrorToReadableJson(error); + + Logger.error( + { + formattedError: err, + error + }, + `Getting Indicator Details Failed` + ); + throw error; + } +}; + +module.exports = getIndicatorDetails; diff --git a/server/queries/getIndicators.js b/server/queries/getIndicators.js index a3c005d..713a6df 100644 --- a/server/queries/getIndicators.js +++ b/server/queries/getIndicators.js @@ -14,21 +14,23 @@ const getIndicators = async (entities, options) => { const indicatorsRequests = map((entity) => { const request = { resultId: entity.value, - route: `technical-intelligence/v1/simple`, + route: `technical-intelligence/v2/indicators`, qs: { - limit: options.limit, - hide_noisy_tags: true, + include_total_count: true, + sort: 'modified_at:desc', ...buildQuery(entity) }, options }; - if (options.indicatorSearchWindow.value !== '0') { - request.qs.start_date = options.indicatorSearchWindow.value; + const modifiedAfter = getModifiedAfter(options.indicatorSearchWindow.value); + + if (modifiedAfter) { + request.qs.modified_after = modifiedAfter; } return request; }, entities); - const indicators = await requestsInParallel(indicatorsRequests, 'body'); + const indicators = await requestsInParallel(indicatorsRequests, 'body.items'); return indicators; } catch (error) { @@ -45,43 +47,47 @@ const getIndicators = async (entities, options) => { }; const buildQuery = (entity) => { - if (entity.isIP) { - return { - query: entity.value, - types: 'ip-dst|port,ip-dst,ip-src,ip-src|port' - }; - } - if (entity.isDomain) { - return { - query: entity.value, - types: 'domain,url' - }; - } - if (entity.isEmail) { - return { - // Note that emails do not have a specific type so we do an exact match search as the - // next best option - query: `"${entity.value}"` - }; - } - if (entity.isMD5) { - return { - query: entity.value, - types: 'md5' - }; - } - if (entity.isSHA1) { - return { - query: entity.value, - types: 'sha1' - }; + const query = { + ioc_value: entity.value + }; + + const iocTypes = getIocTypes(entity); + if (iocTypes) { + query.ioc_types = iocTypes; } - if (entity.isSHA256) { - return { - query: entity.value, - types: 'sha256' - }; + + return query; +}; + +const getIocTypes = (entity) => { + if (entity.isIPv4) return 'ipv4'; + if (entity.isIPv6) return 'ipv6'; + if (entity.isIP) return 'ipv4,ipv6'; + if (entity.isDomain) return 'domain'; + if (entity.isURL) return 'url'; + if (entity.isMD5 || entity.isSHA1 || entity.isSHA256) return 'file'; + return null; +}; + +const getModifiedAfter = (option) => { + if (!option || option === '0') return null; + + const match = /^(\d+)([dMy])$/i.exec(option); + if (!match) return null; + + const amount = Number(match[1]); + const unit = match[2].toLowerCase(); + const now = new Date(); + + if (unit === 'd') { + now.setDate(now.getDate() - amount); + } else if (unit === 'm') { + now.setMonth(now.getMonth() - amount); + } else if (unit === 'y') { + now.setFullYear(now.getFullYear() - amount); } + + return now.toISOString().split('T')[0]; }; module.exports = getIndicators; diff --git a/server/queries/index.js b/server/queries/index.js index bd615f5..7f45e8e 100644 --- a/server/queries/index.js +++ b/server/queries/index.js @@ -4,6 +4,7 @@ const getReportById = require('./getReportById'); const getVulnerability = require('./getVulnerability'); const getEvent = require('./getEvent'); const getReportImage = require('./getReportImage'); +const getIndicatorDetails = require('./getIndicatorDetails'); module.exports = { getIndicators, @@ -11,5 +12,6 @@ module.exports = { getVulnerability, getEvent, getReportById, - getReportImage + getReportImage, + getIndicatorDetails }; diff --git a/server/request.js b/server/request.js index 297a2a4..0993fbf 100644 --- a/server/request.js +++ b/server/request.js @@ -5,7 +5,14 @@ const { requests: { createRequestWithDefaults }, logging: { setLogger, getLogger } } = require('polarity-integration-utils'); -const config = require('../config/config'); +const config = {}; +config.request = { + cert: '', + key: '', + passphrase: '', + ca: '', + proxy: '' +}; const requestWithDefaults = createRequestWithDefaults({ config,