Repository: OWASP/threat-dragon (js)

Issue:
Add API for repository provider
**Describe what problem your feature request solves**
The repository provider may be github or github enterprise, or even some other provider, and there needs to be a way for applications to determine this.

**Describe the solution you'd like**
provide a new API on the express server that provides this information as a JSON  object:

```
{
  protocol: env.get().config.ENTERPRISE_PROTOCOL || 'https',
  hostname: env.get().config.GITHUB_ENTERPRISE_HOSTNAME || 'www.github.com',
  port: env.get().config.GITHUB_ENTERPRISE_PORT || '',
}
```


**Additional context**
This will unblock pull request #546 


Pull request description:
Add server API for provider details
**Summary**
This add a new server API that provides the organisation details off the provider.
This will help to unblock pull-request #546 

**Description for the changelog**
Add server API for provider organisation details

**Other info**
Closes #568 


Patch:
diff --git a/docs/development/api.md b/docs/development/api.md
index 28f769fe..002fc87e 100644
--- a/docs/development/api.md
+++ b/docs/development/api.md
@@ -39,6 +39,7 @@ APIs with no authorisation:
 | `/api/logout` | GET | Logout that will always succeed |
 | `/api/oauth/return` | GET | OAuth return request |
 | `/api/oauth/:provider` | GET | Provides access and refresh tokens if authorised |
+| `/api/threatmodel/organization` | GET | Provides github organisation hostname |
 
 Support for CI/CD pipelines is being worked on, and this API may include:
 * project status
diff --git a/td.server/src/config/routes.config.js b/td.server/src/config/routes.config.js
index e31bc601..498f9af9 100644
--- a/td.server/src/config/routes.config.js
+++ b/td.server/src/config/routes.config.js
@@ -16,6 +16,8 @@ const unauthRoutes = (router) => {
     router.get('/', homeController.index);
     router.get('/healthz', healthcheck.healthz);
 
+    router.get('/api/threatmodel/organisation', threatmodelController.organisation);
+
     router.get('/api/login/:provider', auth.login);
     router.get('/api/logout', auth.logout);
     router.get('/api/oauth/return', auth.oauthReturn);
diff --git a/td.server/src/controllers/threatmodelcontroller.js b/td.server/src/controllers/threatmodelcontroller.js
index 86db5ddb..6a82554d 100644
--- a/td.server/src/controllers/threatmodelcontroller.js
+++ b/td.server/src/controllers/threatmodelcontroller.js
@@ -1,3 +1,4 @@
+import env from '../env/Env.js';
 import loggerHelper from '../helpers/logger.helper.js';
 import repository from '../repositories/threatmodelrepository.js';
 import responseWrapper from './responseWrapper.js';
@@ -148,12 +149,24 @@ const getPagination = (headers, page) => {
     return pagination;
 };
 
+const organisation = (req, res) => {
+    const organisation = {
+        protocol: env.get().config.ENTERPRISE_PROTOCOL || 'https',
+        hostname: env.get().config.GITHUB_ENTERPRISE_HOSTNAME || 'www.github.com',
+        port: env.get().config.GITHUB_ENTERPRISE_PORT || '',
+    };
+    logger.debug('API organisation request: ' + req);
+
+    return res.status(200).send(organisation);
+};
+
 export default {
     branches,
     create,
     deleteModel,
     model,
     models,
+    organisation,
     repos,
     update
 };
diff --git a/td.vue/src/main.desktop.js b/td.vue/src/main.desktop.js
index 85dcd8af..0beea5bc 100644
--- a/td.vue/src/main.desktop.js
+++ b/td.vue/src/main.desktop.js
@@ -21,7 +21,7 @@ Vue.config.productionTip = false;
 
 // Detect the user agent when the `nodeIntegration` option is set to false
 if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
-    console.log('Electron navigator running for renderer')
+    console.log('Electron navigator running for renderer');
 }
 
 // informing renderer that desktop menu shell has closed the model
diff --git a/td.vue/src/service/api/threatmodelApi.js b/td.vue/src/service/api/threatmodelApi.js
index c92ee331..0201f13f 100644
--- a/td.vue/src/service/api/threatmodelApi.js
+++ b/td.vue/src/service/api/threatmodelApi.js
@@ -8,6 +8,13 @@ const extractRepoParts = (fullRepoName) => {
     return { org, repo };
 };
 
+
+/**
+ * Gets the organisation data configured for the express server
+ * @returns {Promise}
+ */
+const organisationAsync = () => api.getAsync(`${resource}/organisation`);
+
 /**
  * Gets the repos for the given user
  * @returns {Promise}
@@ -56,6 +63,7 @@ export default {
     branchesAsync,
     modelAsync,
     modelsAsync,
+    organisationAsync,
     reposAsync,
     updateAsync
 };


Test patch:
diff --git a/docs/development/testing/adhoc.md b/docs/development/testing/adhoc.md
new file mode 100644
index 00000000..a04d26d8
--- /dev/null
+++ b/docs/development/testing/adhoc.md
@@ -0,0 +1,41 @@
+---
+layout: page
+title: AdHoc Testing
+nav_order: 2
+path: /testing/adhoc
+group: Testing
+---
+
+# Ad-Hoc Testing
+
+During development it can be convenient to check functionality of the front and back ends
+in an ad-hoc way which is not part of the unit and end-to-end tests. 
+
+## Back-end server
+The web application express server can be run locally using command `pnpm start:server` from the top level directory.
+The server will need access to environment variables as shown in [environment setup](development/env).
+
+When running locally it may be that HTTPS certificates are not present; consider using these environment variables:
+
+```
+NODE_ENV=development
+LOG_LEVEL=debug
+SERVER_API_PROTOCOL=http
+```
+
+A browser can be used to access the server, or other command line tools such as curl: 
+
+```
+curl -v http://localhost:3000/api/threatmodel/organisation  \
+     -H "Accept: application/json"
+```
+
+## Desktop server
+The desktop application uses electron as the back-end server.
+Use command `pnpm start:desktop` to run the application in development mode,
+it will rebuild and launch when source files are changed.
+
+## Front-end application
+The front end application can be tested in most browsers along with the browser supplied developer tools.
+If the application is being tested in the desktop environment then electron uses
+chrome as the renderer, with chrome developer tools being available.
diff --git a/docs/development/testing/unit.md b/docs/development/testing/unit.md
index d59f7026..85956eab 100644
--- a/docs/development/testing/unit.md
+++ b/docs/development/testing/unit.md
@@ -5,6 +5,7 @@ nav_order: 0
 path: /testing/unit
 group: Testing
 ---
+
 # Unit Testing
 
 <div class="card">
diff --git a/td.server/test/config/routes.config.spec.js b/td.server/test/config/routes.config.spec.js
index 8655c7b0..799b788e 100644
--- a/td.server/test/config/routes.config.spec.js
+++ b/td.server/test/config/routes.config.spec.js
@@ -95,6 +95,13 @@ describe('config/routes.config.js routes', () => {
             );
         });
         
+        it('routes GET /api/threatmodel/organisation', () => {
+            expect(mockRouter.get).to.have.been.calledWith(
+                '/api/threatmodel/organisation',
+                threatmodelController.organisation
+            );
+        });
+        
         it('routes GET /api/threatmodel/:organisation/:repo/:branch/models', () => {
             expect(mockRouter.get).to.have.been.calledWith(
                 '/api/threatmodel/:organisation/:repo/:branch/models',
diff --git a/td.vue/tests/unit/service/api/threatmodelApi.spec.js b/td.vue/tests/unit/service/api/threatmodelApi.spec.js
index 6595b5c9..6762163a 100644
--- a/td.vue/tests/unit/service/api/threatmodelApi.spec.js
+++ b/td.vue/tests/unit/service/api/threatmodelApi.spec.js
@@ -7,6 +7,16 @@ describe('service/threatmodelApi.js', () => {
         jest.spyOn(api, 'putAsync').mockImplementation(() => {});
     });
 
+    describe('organisationAsync', () => {
+        beforeEach(async () => {
+            await threatmodelApi.organisationAsync();
+        });
+
+        it('calls the organisation endpoint', () => {
+            expect(api.getAsync).toHaveBeenCalledWith('/api/threatmodel/organisation');
+        });
+    });
+
     describe('reposAsync', () => {
         beforeEach(async () => {
             await threatmodelApi.reposAsync();