Repository: OWASP/threat-dragon (js)

Issue:
Provide Close button instead of Delete button
**Describe what problem your feature request solves**
Delete of threat models is not used, and the Delete button does nothing

**Describe the solution you'd like**
Provide a Close button instead of the existing Delete button, this button should return the user to the main dashboard after closing the threat model

**Additional context**


Pull request:
provide threat model close button
**Summary**
Removes delete of threat model functionality
Provides a Close button instead of a Delete button

**Description for the changelog**
provide threat model close button

**Other info**
closes #578 


Patch:
diff --git a/docs/development/api.md b/docs/development/api.md
index 002fc87e..8dc3a569 100644
--- a/docs/development/api.md
+++ b/docs/development/api.md
@@ -12,7 +12,7 @@ At present it there is a minimal application programming interface for
 [Threat Dragon](http://owasp.org/www-project-threat-dragon) .
 This API is used to access to threat models stored by repository providers, github being the first.
 
-APIs protected by authorisation, including threat model CRUD:
+APIs protected by authorisation, including threat model Create, Read, Update (but no Delete):
 
 {:.table .table-striped}
 | Path | Action | Description |
@@ -23,7 +23,6 @@ APIs protected by authorisation, including threat model CRUD:
 | `/api/threatmodel/:organisation/:repo/branches` | GET | List branches for a given repository |
 | `/api/threatmodel/:organisation/:repo/:branch/models` | GET | List models for a given branch and repository |
 | `/api/threatmodel/:organisation/:repo/:branch/:model/data` | GET | Reads the threat model contents for a given model |
-| `/api/threatmodel/:organisation/:repo/:branch/:model` | DELETE | Delete a model from a given branch and repository |
 | `/api/threatmodel/:organisation/:repo/:branch/:model/create` | PUT | Creates a new model in the given branch and repository |
 | `/api/threatmodel/:organisation/:repo/:branch/:model/update` | PUT | Update a model in the given branch and repository |
 
diff --git a/td.server/src/config/routes.config.js b/td.server/src/config/routes.config.js
index 498f9af9..121ad271 100644
--- a/td.server/src/config/routes.config.js
+++ b/td.server/src/config/routes.config.js
@@ -39,7 +39,8 @@ const routes = (router) => {
     router.get('/api/threatmodel/:organisation/:repo/:branch/models', threatmodelController.models);
     router.get('/api/threatmodel/:organisation/:repo/:branch/:model/data', threatmodelController.model);
 
-    router.delete('/api/threatmodel/:organisation/:repo/:branch/:model', threatmodelController.deleteModel);
+    // removed because of security denial of service concerns (denial of models)
+    //router.delete('/api/threatmodel/:organisation/:repo/:branch/:model', threatmodelController.deleteModel);
 
     router.put('/api/threatmodel/:organisation/:repo/:branch/:model/create', threatmodelController.create);
     router.put('/api/threatmodel/:organisation/:repo/:branch/:model/update', threatmodelController.update);
diff --git a/td.vue/src/views/ThreatModel.vue b/td.vue/src/views/ThreatModel.vue
index 694128c1..3be237aa 100644
--- a/td.vue/src/views/ThreatModel.vue
+++ b/td.vue/src/views/ThreatModel.vue
@@ -65,10 +65,10 @@
                         icon="file-alt"
                         :text="$t('forms.report')" />
                     <td-form-button
-                        id="td-delete-btn"
-                        :onBtnClick="onDeleteClick"
+                        id="td-close-btn"
+                        :onBtnClick="onCloseClick"
                         icon="times"
-                        :text="$t('forms.delete')" />
+                        :text="$t('forms.close')" />
                 </b-btn-group>
             </b-col>
         </b-row>
@@ -100,7 +100,7 @@ import { mapState } from 'vuex';
 import { getProviderType } from '@/service/provider/providers.js';
 import TdFormButton from '@/components/FormButton.vue';
 import TdThreatModelSummaryCard from '@/components/ThreatModelSummaryCard.vue';
-import { THREATMODEL_DIAGRAM_SELECTED } from '@/store/actions/threatmodel.js';
+import { THREATMODEL_CLEAR, THREATMODEL_DIAGRAM_SELECTED } from '@/store/actions/threatmodel.js';
 
 export default {
     name: 'ThreatModel',
@@ -121,9 +121,10 @@ export default {
             evt.preventDefault();
             this.$router.push({ name: `${this.providerType}Report`, params: this.$route.params });
         },
-        onDeleteClick(evt) {
+        onCloseClick(evt) {
             evt.preventDefault();
-            console.log('Delete clicked! Action TBA');
+            this.$store.dispatch(THREATMODEL_CLEAR);
+            this.$router.push('/dashboard');
         },
         getThumbnailUrl(diagram) {
             if (!diagram || !diagram.diagramType) {


Test patch:
diff --git a/td.server/test/config/routes.config.spec.js b/td.server/test/config/routes.config.spec.js
index 799b788e..e0c9d839 100644
--- a/td.server/test/config/routes.config.spec.js
+++ b/td.server/test/config/routes.config.spec.js
@@ -116,12 +116,13 @@ describe('config/routes.config.js routes', () => {
             );
         });
         
-        it('routes DELETE /api/threatmodel/:organisation/:repo/:branch/:model', () => {
+        // removed because of security denial of service concerns (denial of models)
+        /* it('routes DELETE /api/threatmodel/:organisation/:repo/:branch/:model', () => {
             expect(mockRouter.delete).to.have.been.calledWith(
                 '/api/threatmodel/:organisation/:repo/:branch/:model',
                 threatmodelController.deleteModel
             );
-        });
+        });*/
         
         it('routes PUT /api/threatmodel/:organisation/:repo/:branch/:model/create', () => {
             expect(mockRouter.put).to.have.been.calledWith(
diff --git a/td.vue/tests/e2e/specs/threatmodel/close.cy.js b/td.vue/tests/e2e/specs/threatmodel/close.cy.js
new file mode 100644
index 00000000..a122c14f
--- /dev/null
+++ b/td.vue/tests/e2e/specs/threatmodel/close.cy.js
@@ -0,0 +1,17 @@
+describe('closing a threat model', () => {
+    beforeEach(() => {
+        cy.get('#local-login-btn').click();
+        cy.get('a[href="#/demo/select"]').click();
+        cy.get('a[data-model-name="Version 2 New Model"').click();
+        cy.url().should('contain', '/local/Version%202%20New%20Model');
+        cy.contains('New Threat Model');
+    });
+
+    describe('Close', () => {
+        it('goes back without prompting if data has not been edited', () => {
+            cy.get('#td-close-btn').click();
+            cy.url().should('equal', Cypress.config().baseUrl + '#/dashboard');
+        });
+    });
+
+});
diff --git a/td.vue/tests/e2e/specs/threatmodel/edit-actions.cy.js b/td.vue/tests/e2e/specs/threatmodel/edit.cy.js
similarity index 100%
rename from td.vue/tests/e2e/specs/threatmodel/edit-actions.cy.js
rename to td.vue/tests/e2e/specs/threatmodel/edit.cy.js
diff --git a/td.vue/tests/e2e/specs/threatmodel/import.cy.js b/td.vue/tests/e2e/specs/threatmodel/import.cy.js
index 28a01ad4..d3db9db7 100644
--- a/td.vue/tests/e2e/specs/threatmodel/import.cy.js
+++ b/td.vue/tests/e2e/specs/threatmodel/import.cy.js
@@ -72,7 +72,7 @@ describe('import', () => {
             cy.contains('New threat model');
             cy.get('#td-edit-btn').should('be.visible');
             cy.get('#td-report-btn').should('be.visible');
-            cy.get('#td-delete-btn').should('be.visible');
+            cy.get('#td-close-btn').should('be.visible');
         });
     });
 
@@ -139,7 +139,7 @@ describe('import', () => {
             cy.contains('Main Request Data Flow');
             cy.get('#td-edit-btn').should('be.visible');
             cy.get('#td-report-btn').should('be.visible');
-            cy.get('#td-delete-btn').should('be.visible');
+            cy.get('#td-close-btn').should('be.visible');
         });
     });
 
diff --git a/td.vue/tests/unit/views/threatmodel.spec.js b/td.vue/tests/unit/views/threatmodel.spec.js
index be679c5c..128b91c8 100644
--- a/td.vue/tests/unit/views/threatmodel.spec.js
+++ b/td.vue/tests/unit/views/threatmodel.spec.js
@@ -108,17 +108,17 @@ describe('views/Threatmodel.vue', () => {
             });
         });
 
-        describe('delete', () => {
+        describe('close', () => {
             beforeEach(async () => {
-                await wrapper.find('#td-delete-btn').trigger('click', evt);
+                await wrapper.find('#td-close-btn').trigger('click', evt);
             });
 
             it('prevents the default event', () => {
                 expect(evt.preventDefault).toHaveBeenCalledTimes(1);
             });
 
-            it('logs to the console and needs to be removed...', () => {
-                expect(console.log).toHaveBeenCalled();
+            it('returns to the Dashboard view', () => {
+                expect(mockRouter.push).toHaveBeenCalledWith('/dashboard');
             });
         });