From b64551ee49da532d46fbf44b8c9928e0ab987356 Mon Sep 17 00:00:00 2001 From: Jason Minnick Date: Tue, 14 Jul 2020 15:27:42 -0400 Subject: [PATCH] definition update. handle duplicate relationships --- app/package-lock.json | 22 +++++++++++++ app/package.json | 1 + app/src/components/Canvas.js | 10 +++--- app/src/definition-adapters/Malware.js | 15 +++++++++ app/src/stores/App.js | 45 +++++++++++++++++++++++--- app/webpack/webpack.common.js | 16 ++------- app/webpack/webpack.dev.js | 3 ++ 7 files changed, 87 insertions(+), 25 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index a8f1815..17cd754 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1095,6 +1095,28 @@ "minimist": "^1.2.0" } }, + "@hot-loader/react-dom": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.13.0.tgz", + "integrity": "sha512-lJZrmkucz2MrQJTQtJobx5MICXcfQvKihszqv655p557HPi0hMOWxrNpiHv3DWD8ugNWjtWcVWqRnFvwsHq1mQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.0" + }, + "dependencies": { + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } + }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", diff --git a/app/package.json b/app/package.json index 089c924..3e47c9e 100644 --- a/app/package.json +++ b/app/package.json @@ -70,6 +70,7 @@ "react": "16.12.0", "react-datepicker": "^2.16.0", "react-dom": "16.12.0", + "@hot-loader/react-dom": "^16.12.0", "react-hot-loader": "4.12.18", "react-router-dom": "^5.1.2", "react-tooltip": "^4.2.6", diff --git a/app/src/components/Canvas.js b/app/src/components/Canvas.js index d2a5fd1..b6e7aa4 100644 --- a/app/src/components/Canvas.js +++ b/app/src/components/Canvas.js @@ -23,6 +23,10 @@ export default class Canvas extends React.Component { constructor(props) { super(props); + document.addEventListener("dragover", (e) => { + this.store.setMousePosition(e); + }, false); + this.store = this.props.store.appStore; this.generateNodeID = this.generateNodeID.bind(this); @@ -67,12 +71,6 @@ export default class Canvas extends React.Component { this.onClickHideSubmissionErrorHandler = this.onClickHideSubmissionErrorHandler.bind(this); } - componentWillMount() { - document.addEventListener("dragover", (e) => { - this.store.setMousePosition(e); - }, false); - } - componentWillUnmount() { document.removeEventListener("dragover", (e) => { }, false); diff --git a/app/src/definition-adapters/Malware.js b/app/src/definition-adapters/Malware.js index 9f8da44..4ca09ef 100644 --- a/app/src/definition-adapters/Malware.js +++ b/app/src/definition-adapters/Malware.js @@ -12,15 +12,30 @@ class Malware extends Base { "prefix": "malware--", "active": true, "relationships": [ + {"type": "authored-by", "target": "threat-actor"}, + {"type": "authored-by", "target": "intrusion-set"}, {"type": "targets", "target": "identity"}, {"type": "beacons-to", "target": "infrastructure"}, {"type": "exfiltrates-to", "target": "infrastructure"}, + {"type": "communicates-with", "target": "observable", "sub-target": "ipv4-addr"}, + {"type": "communicates-with", "target": "observable", "sub-target": "ipv6-addr"}, + {"type": "communicates-with", "target": "observable", "sub-target": "domain-name"}, + {"type": "communicates-with", "target": "observable", "sub-target": "url"}, {"type": "compromises", "target": "infrastructure"}, {"type": "targets", "target": "vulnerability"}, {"type": "targets", "target": "infrastructure"}, {"type": "uses", "target": "infrastructure"}, {"type": "uses", "target": "tool"}, + {"type": "uses", "target": "malware"}, + {"type": "uses", "target": "attack-pattern"}, {"type": "variant-of", "target": "malware"}, + {"type": "controls", "target": "malware"}, + {"type": "downloads", "target": "malware"}, + {"type": "drops", "target": "malware"}, + {"type": "downloads", "target": "tool"}, + {"type": "drops", "target": "tool"}, + {"type": "downloads", "target": "observable", "sub-target": "file"}, + {"type": "drops", "target": "observable", "sub-target": "file"}, {"type": "identifies", "target": "observable", "sub-target": "artifact", "x_embed": "sample_refs"}, {"type": "operates-on", "target": "observable", "sub-target": "software", "x_embed": "operating_system_refs"}, {"type": "identifies", "target": "artifact", "x_embed": "sample_refs"}, diff --git a/app/src/stores/App.js b/app/src/stores/App.js index 6d63c49..c299eba 100644 --- a/app/src/stores/App.js +++ b/app/src/stores/App.js @@ -530,13 +530,27 @@ export default class App { const nodeOnScreenType = nodeOnScreen.properties.type.enum[0]; const draggingType = this.dragging.properties.type.enum[0]; + const alredyPushed = (rel, relationship) => { + let found = false; + + rel.map(r => { + let t = relationship["sub-target"] ? relationship["sub-target"] : relationship.target; + + if (r.targetObjectType === t && r.relationship_type === relationship.type) { + found = true; + } + }); + + return found; + } + let rel = []; if (nodeOnScreen.id !== this.dragging.id) { nodeOnScreen.relationships.map(relationship => { if (relationship.target === draggingType) { let madeRel = this.makeRelationship(nodeOnScreen, this.dragging, relationship); - if (madeRel) { + if (madeRel && !alredyPushed(rel, relationship)) { rel.push(madeRel); } } @@ -545,7 +559,7 @@ export default class App { this.dragging.relationships.map(relationship => { if (relationship.target === nodeOnScreenType) { let madeRel = this.makeRelationship(this.dragging, nodeOnScreen, relationship); - if (madeRel) { + if (madeRel && !alredyPushed(rel, relationship)) { rel.push(madeRel); } } @@ -773,7 +787,6 @@ export default class App { } catch (e) { this.growlMessage = "Incorrect JSON Syntax."; this.showGrowl = true; - console.warn(e); } } @@ -886,7 +899,7 @@ export default class App { nodes.map(node => { for (let key in node.properties) { - if (node.required.indexOf(key) > -1) { + if (node.required && node.required.indexOf(key) > -1) { // For required refs check the bundle // instead of the node. if (key.indexOf("_refs") > -1) { @@ -950,6 +963,26 @@ export default class App { submit() { this.validateSubmission(); + const pruneRelationshipObjectProperties = (bundle) => { + let pruneList = [ + "targetObjectType", + "subTarget" + ]; + + bundle.objects.map(o => { + if (o.type === "relationship") { + for (let key in o) { + if (pruneList.indexOf(key) > -1) { + delete o[key]; + } + } + } + }); + + return bundle; + } + + if (!this.failedCollection.length) { let bundle = _cloneDeep(this.bundle); @@ -965,7 +998,7 @@ export default class App { delete o[key]; } } else { - if (!o[key].length) { + if (o[key] && !o[key].length) { delete o[key]; } } @@ -973,6 +1006,8 @@ export default class App { } }); + bundle = pruneRelationshipObjectProperties(bundle); + /*** TODO plumb in your API call **/ diff --git a/app/webpack/webpack.common.js b/app/webpack/webpack.common.js index 87dc4db..20acf90 100644 --- a/app/webpack/webpack.common.js +++ b/app/webpack/webpack.common.js @@ -16,22 +16,10 @@ module.exports = { loader: 'skeleton-loader', options: {procedure: content => `${content}export default LeaderLine`} }] - }, - // { - // enforce: 'pre', - // test: /\.(js|jsx)$/, - // // loader: 'eslint-loader', - // exclude: /(node_modules)/, - // options: { - // // formatter: eslint.CLIEngine.getFormatter('stylish'), - // // emitWarning: process.env.NODE_ENV !== 'production', - // }, - // }, - { + },{ test: /\.exec\.js$/, use: ['script-loader'] - }, - { + },{ test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /(node_modules)/, diff --git a/app/webpack/webpack.dev.js b/app/webpack/webpack.dev.js index 913cd54..e015dd7 100644 --- a/app/webpack/webpack.dev.js +++ b/app/webpack/webpack.dev.js @@ -4,6 +4,9 @@ const commonPaths = require('./paths'); module.exports = { mode: 'development', + resolve: { + alias: { 'react-dom': '@hot-loader/react-dom' } + }, output: { filename: '[name].js', path: commonPaths.outputPath,