This is an automated email from the ASF dual-hosted git repository.
ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new 72e93a1602 TPv1 Add the ability to inspect a cert/DS (#7618)
72e93a1602 is described below
commit 72e93a1602131faa3059841a67a28c3215c56aaf
Author: Steve Hamrick <[email protected]>
AuthorDate: Mon Jul 10 00:25:35 2023 -0600
TPv1 Add the ability to inspect a cert/DS (#7618)
* Implement cert inspector in tpv1
* Add changelog
---------
Co-authored-by: Steve Hamrick <[email protected]>
Co-authored-by: ocket8888 <[email protected]>
---
CHANGELOG.md | 1 +
traffic_portal/app/src/app.js | 3 +
.../FormDeliveryServiceSslKeysController.js | 5 +
.../form.deliveryServiceSslKeys.tpl.html | 174 +++++++++++-------
.../modules/form/ssl/CertInspectController.js | 35 ++++
.../src/common/modules/form/ssl/_inspect-ssl.scss | 25 +++
.../common/modules/form/ssl/cert-inspect.tpl.html | 47 +++++
.../app/src/common/modules/form/ssl/index.js | 16 ++
.../common/modules/navigation/navigation.tpl.html | 1 +
.../src/common/modules/ssl/CertAuthorController.js | 36 ++++
.../app/src/common/modules/ssl/CertViewer.d.ts | 44 +++++
.../src/common/modules/ssl/CertViewerController.js | 200 +++++++++++++++++++++
.../app/src/common/modules/ssl/_ssl.scss | 28 +++
.../src/common/modules/ssl/cert-author.tpl.html | 66 +++++++
.../app/src/common/modules/ssl/cert-view.tpl.html | 99 ++++++++++
traffic_portal/app/src/common/modules/ssl/index.js | 17 ++
.../app/src/modules/private/ssl/index.js | 28 +++
.../src/modules/private/ssl/inspect-cert.tpl.html | 18 ++
traffic_portal/app/src/scripts/shared-libs.js | 3 +
traffic_portal/app/src/styles/main.scss | 2 +
traffic_portal/package-lock.json | 59 ++++--
traffic_portal/package.json | 4 +-
22 files changed, 833 insertions(+), 78 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60d99aad61..6abfae4288 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- [#7543](https://github.com/apache/trafficcontrol/pull/7543) *Traffic Portal*
New Ansible Role to use Traffic Portal v2
- [#7516](https://github.com/apache/trafficcontrol/pull/7516) *t3c* added
command line arg to control go_direct in parent.config
- [#7602](https://github.com/apache/trafficcontrol/pull/7602) *t3c* added
installed package data to t3c-apply-metadata.json
+- [#7618](https://github.com/apache/trafficcontrol/pull/7618) *Traffic Portal*
Add the ability to inspect a user provider cert, or the cert chain on DS SSL
keys.
- [#7619](https://github.com/apache/trafficcontrol/pull/7619) Traffic Ops*
added optional field `oauth_user_attribute` for OAuth login credentials
### Changed
diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js
index 92bf0ddec0..e4de35b0b8 100644
--- a/traffic_portal/app/src/app.js
+++ b/traffic_portal/app/src/app.js
@@ -72,6 +72,7 @@ var trafficPortal = angular.module('trafficPortal', [
require('./modules/private/capabilities/users').name,
require('./modules/private/cdns').name,
require('./modules/private/cdns/config').name,
+ require("./modules/private/ssl").name,
require('./modules/private/cdns/deliveryServices').name,
require('./modules/private/cdns/dnssecKeys').name,
require('./modules/private/cdns/dnssecKeys/generate').name,
@@ -260,6 +261,7 @@ var trafficPortal = angular.module('trafficPortal', [
require('./common/modules/locks').name,
require('./common/modules/message').name,
require('./common/modules/navigation').name,
+ require("./common/modules/ssl").name,
require('./common/modules/notifications').name,
require('./common/modules/release').name,
@@ -334,6 +336,7 @@ var trafficPortal = angular.module('trafficPortal', [
require('./common/modules/form/serviceCategory').name,
require('./common/modules/form/serviceCategory/edit').name,
require('./common/modules/form/serviceCategory/new').name,
+ require("./common/modules/form/ssl").name,
require('./common/modules/form/status').name,
require('./common/modules/form/status/edit').name,
require('./common/modules/form/status/new').name,
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js
b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js
index 64a2644665..4037e35dc9 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js
+++
b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js
@@ -87,6 +87,11 @@ var FormDeliveryServiceSslKeysController =
function(deliveryService, sslKeys, $s
locationUtils.navigateToPath('/delivery-services/' +
deliveryService.id + '/ssl-keys/generate');
};
+ $scope.navState = 0;
+ $scope.updateState = function(newState) {
+ $scope.navState = newState;
+ }
+
$scope.renewCert = function() {
var params = {
title: 'Renew SSL Keys for Delivery Service: ' +
deliveryService.xmlId
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html
index 053489d19c..fd59128b30 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html
@@ -21,12 +21,15 @@ under the License.
<div class="x_title">
<ol class="breadcrumb pull-left">
<li><a ng-click="navigateToPath('/delivery-services')">Delivery
Services</a></li>
- <li><a ng-click="navigateToPath('/delivery-services/' +
deliveryService.id + '?dsType=' +
deliveryService.type)">{{deliveryService.xmlId}}</a></li>
+ <li>
+ <a ng-click="navigateToPath('/delivery-services/' +
deliveryService.id + '?dsType=' +
deliveryService.type)">{{deliveryService.xmlId}}</a>
+ </li>
<li class="active">SSL keys</li>
</ol>
<div class="pull-right" role="group">
<div class="btn-group" role="group" uib-dropdown
is-open="more.isopen">
- <button type="button" class="btn btn-default dropdown-toggle"
uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+ <button type="button" class="btn btn-default dropdown-toggle"
uib-dropdown-toggle aria-haspopup="true"
+ aria-expanded="false">
More
<span class="caret"></span>
</button>
@@ -39,69 +42,112 @@ under the License.
<div class="clearfix"></div>
</div>
<div class="x_content">
- <br>
- <form name="dsSslKeyForm" class="form-horizontal form-label-left"
novalidate>
- <div class="form-group">
- <label for="version" class="control-label col-md-2 col-sm-2
col-xs-12">Version</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <input id="version" name="version" type="text"
class="form-control" ng-model="sslKeys.version" readonly>
- </div>
+ <ul class="nav nav-tabs" role="tablist">
+ <li role="presentation" ng-class="{active: navState === 0 }">
+ <a data-toggle="tab" ng-click="updateState(0)">Stored</a>
+ </li>
+ <li role="presentation" ng-class="{active: navState === 1 }">
+ <a data-toggle="tab" ng-click="updateState(1)">Processed</a>
+ </li>
+ </ul>
+ <br >
+ <div class="tab-content">
+ <div class="tab-pane" role="tabpanel" ng-class="{show: navState
=== 0 }">
+ <form name="dsSslKeyForm" class="form-horizontal
form-label-left" novalidate>
+ <div class="form-group">
+ <label for="version" class="control-label col-md-2
col-sm-2 col-xs-12">Version</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input id="version" name="version" type="text"
class="form-control" ng-model="sslKeys.version"
+ readonly>
+ </div>
+ </div>
+ <div class="form-group"
+ ng-class="{'has-error':
hasError(dsSslKeyForm.hostname), 'has-feedback':
hasError(dsSslKeyForm.hostname)}">
+ <label for="hostname" class="control-label col-md-2
col-sm-2 col-xs-12">Common Name *</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input id="hostname" name="hostname" type="text"
class="form-control" ng-model="sslKeys.hostname"
+ required autofocus>
+ <small class="input-error"
+
ng-show="hasPropertyError(dsSslKeyForm.hostname, 'required')">Required</small>
+ <span ng-show="hasError(dsSslKeyForm.hostname)"
class="form-control-feedback"><i
+ class="fa fa-times"></i></span>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="expiration" class="control-label col-md-2
col-sm-2 col-xs-12">Expiration</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <output name="expiration"
class="form-control">{{formattedExpiration}}</output>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="sans" class="control-label col-md-2
col-sm-2 col-xs-12">SANs</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <output name="sans"
class="form-control">{{sans}}</output>
+ </div>
+ </div>
+ <div class="form-group"
+ ng-class="{'has-error':
hasError(dsSslKeyForm.authType), 'has-feedback':
hasError(dsSslKeyForm.authType)}">
+ <label for="authType" class="control-label col-md-2
col-sm-2 col-xs-12">Certificate Source (Self Signed,
+ CA, etc) *</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <select id="authType" name="authType" type="text"
class="form-control" ng-model="acmeProvider"
+ ng-options="acmeProviderOption as
acmeProviderOption for acmeProviderOption in acmeProviders"
+ ng-change="updateProvider()"
required></select>
+ <small class="input-error"
+
ng-show="hasPropertyError(dsSslKeyForm.authType, 'required')">Required</small>
+ <span ng-show="hasError(dsSslKeyForm.authType)"
class="form-control-feedback"><i
+ class="fa fa-times"></i></span>
+ </div>
+ </div>
+ <div class="form-group"
+ ng-class="{'has-error':
hasError(dsSslKeyForm.privateKey), 'has-feedback':
hasError(dsSslKeyForm.privateKey)}">
+ <label for="privateKey" class="control-label col-md-2
col-sm-2 col-xs-12">Private Key *</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <textarea id="privateKey" name="privateKey" type="text"
class="form-control private-text"
+ ng-model="sslKeys.certificate.key" rows="25"
required></textarea>
+ <small class="input-error"
+
ng-show="hasPropertyError(dsSslKeyForm.privateKey, 'required')">Required</small>
+ <span ng-show="hasError(dsSslKeyForm.privateKey)"
class="form-control-feedback"><i
+ class="fa fa-times"></i></span>
+ </div>
+ </div>
+ <div class="form-group"
+ ng-class="{'has-error':
hasError(dsSslKeyForm.certificateSigningRequest), 'has-feedback':
hasError(dsSslKeyForm.certificateSigningRequest)}"
+ ng-if="sslKeys.authType !== 'Lets Encrypt'">
+ <label for="certificateSigningRequest"
class="control-label col-md-2 col-sm-2 col-xs-12">Certificate
+ Signing Request *</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <textarea id="certificateSigningRequest"
name="certificateSigningRequest" type="text"
+ class="form-control"
ng-model="sslKeys.certificate.csr" rows="25"
+ ng-required="sslKeys.authType !== 'Lets
Encrypt'"></textarea>
+ <small class="input-error"
+
ng-show="hasPropertyError(dsSslKeyForm.certificateSigningRequest,
'required')">Required</small>
+ <span
ng-show="hasError(dsSslKeyForm.certificateSigningRequest)"
class="form-control-feedback"><i
+ class="fa fa-times"></i></span>
+ </div>
+ </div>
+ <div class="form-group"
+ ng-class="{'has-error':
hasError(dsSslKeyForm.certificate), 'has-feedback':
hasError(dsSslKeyForm.certificate)}">
+ <label for="certificate" class="control-label col-md-2
col-sm-2 col-xs-12">Certificate *</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <textarea id="certificate" name="certificate" type="text"
class="form-control"
+ ng-model="sslKeys.certificate.crt" rows="25"
required></textarea>
+ <small class="input-error"
+
ng-show="hasPropertyError(dsSslKeyForm.certificate,
'required')">Required</small>
+ <span ng-show="hasError(dsSslKeyForm.certificate)"
class="form-control-feedback"><i
+ class="fa fa-times"></i></span>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-success"
+ ng-disabled="dsSslKeyForm.$pristine ||
dsSslKeyForm.$invalid" ng-click="save()">Update Keys
+ </button>
+ </div>
+ </form>
</div>
- <div class="form-group" ng-class="{'has-error':
hasError(dsSslKeyForm.hostname), 'has-feedback':
hasError(dsSslKeyForm.hostname)}">
- <label for="hostname" class="control-label col-md-2 col-sm-2
col-xs-12">Common Name *</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <input id="hostname" name="hostname" type="text"
class="form-control" ng-model="sslKeys.hostname" required autofocus>
- <small class="input-error"
ng-show="hasPropertyError(dsSslKeyForm.hostname, 'required')">Required</small>
- <span ng-show="hasError(dsSslKeyForm.hostname)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
- </div>
+ <div class="tab-pane" role="tabpanel" ng-class="{show: navState
=== 1 }">
+ <cert-viewer-controller
chain="{{sslKeys.certificate.crt}}"></cert-viewer-controller>
</div>
- <div class="form-group">
- <label for="expiration" class="control-label
col-md-2 col-sm-2 col-xs-12">Expiration</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <output name="expiration"
class="form-control">{{formattedExpiration}}</output>
- </div>
- </div>
- <div class="form-group">
- <label for="sans" class="control-label col-md-2 col-sm-2
col-xs-12">SANs</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <output name="sans" class="form-control">{{sans}}</output>
- </div>
- </div>
- <div class="form-group" ng-class="{'has-error':
hasError(dsSslKeyForm.authType), 'has-feedback':
hasError(dsSslKeyForm.authType)}">
- <label for="authType" class="control-label
col-md-2 col-sm-2 col-xs-12">Certificate Source (Self Signed, CA, etc) *</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <select id="authType" name="authType"
type="text" class="form-control" ng-model="acmeProvider"
ng-options="acmeProviderOption as acmeProviderOption for acmeProviderOption in
acmeProviders" ng-change="updateProvider()" required></select>
- <small class="input-error"
ng-show="hasPropertyError(dsSslKeyForm.authType, 'required')">Required</small>
- <span
ng-show="hasError(dsSslKeyForm.authType)" class="form-control-feedback"><i
class="fa fa-times"></i></span>
- </div>
- </div>
- <div class="form-group" ng-class="{'has-error':
hasError(dsSslKeyForm.privateKey), 'has-feedback':
hasError(dsSslKeyForm.privateKey)}">
- <label for="privateKey" class="control-label col-md-2 col-sm-2
col-xs-12">Private Key *</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <textarea id="privateKey" name="privateKey" type="text"
class="form-control private-text" ng-model="sslKeys.certificate.key" rows="25"
required></textarea>
- <small class="input-error"
ng-show="hasPropertyError(dsSslKeyForm.privateKey, 'required')">Required</small>
- <span ng-show="hasError(dsSslKeyForm.privateKey)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
- </div>
- </div>
- <div class="form-group" ng-class="{'has-error':
hasError(dsSslKeyForm.certificateSigningRequest), 'has-feedback':
hasError(dsSslKeyForm.certificateSigningRequest)}" ng-if="sslKeys.authType !==
'Lets Encrypt'">
- <label for="certificateSigningRequest" class="control-label
col-md-2 col-sm-2 col-xs-12">Certificate Signing Request *</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <textarea id="certificateSigningRequest"
name="certificateSigningRequest" type="text" class="form-control"
ng-model="sslKeys.certificate.csr" rows="25" ng-required="sslKeys.authType !==
'Lets Encrypt'"></textarea>
- <small class="input-error"
ng-show="hasPropertyError(dsSslKeyForm.certificateSigningRequest,
'required')">Required</small>
- <span
ng-show="hasError(dsSslKeyForm.certificateSigningRequest)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
- </div>
- </div>
- <div class="form-group" ng-class="{'has-error':
hasError(dsSslKeyForm.certificate), 'has-feedback':
hasError(dsSslKeyForm.certificate)}">
- <label for="certificate" class="control-label col-md-2
col-sm-2 col-xs-12">Certificate *</label>
- <div class="col-md-10 col-sm-10 col-xs-12">
- <textarea id="certificate" name="certificate" type="text"
class="form-control" ng-model="sslKeys.certificate.crt" rows="25"
required></textarea>
- <small class="input-error"
ng-show="hasPropertyError(dsSslKeyForm.certificate,
'required')">Required</small>
- <span ng-show="hasError(dsSslKeyForm.certificate)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
- </div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-success"
ng-disabled="dsSslKeyForm.$pristine || dsSslKeyForm.$invalid"
ng-click="save()">Update Keys</button>
- </div>
- </form>
+ </div>
</div>
</div>
diff --git
a/traffic_portal/app/src/common/modules/form/ssl/CertInspectController.js
b/traffic_portal/app/src/common/modules/form/ssl/CertInspectController.js
new file mode 100644
index 0000000000..7851525d35
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/form/ssl/CertInspectController.js
@@ -0,0 +1,35 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+let CertInspectController = function ($scope) {
+ $scope.navState = 0;
+ $scope.inputCert = "";
+ $scope.loadCert = "";
+
+ $scope.load = function() {
+ $scope.loadCert = $scope.inputCert;
+ $scope.updateState(1);
+ }
+
+ $scope.updateState = function(state) {
+ if(state === 1 && $scope.loadCert === "") {
+ return;
+ }
+ $scope.navState = state;
+ }
+}
+
+CertInspectController.$inject = ["$scope"];
+module.exports = CertInspectController;
diff --git a/traffic_portal/app/src/common/modules/form/ssl/_inspect-ssl.scss
b/traffic_portal/app/src/common/modules/form/ssl/_inspect-ssl.scss
new file mode 100644
index 0000000000..7ca5e3ecde
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/form/ssl/_inspect-ssl.scss
@@ -0,0 +1,25 @@
+/*!
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#dropZone {
+ border: 2px dashed #bbb;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ padding: 25px;
+ text-align: center;
+ font: 16pt bold;
+ color: #bbb;
+}
diff --git
a/traffic_portal/app/src/common/modules/form/ssl/cert-inspect.tpl.html
b/traffic_portal/app/src/common/modules/form/ssl/cert-inspect.tpl.html
new file mode 100644
index 0000000000..f8c88b4e53
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/form/ssl/cert-inspect.tpl.html
@@ -0,0 +1,47 @@
+<!--
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+<div class="x_panel">
+ <div class="x_title">
+ <ol class="breadcrumb pull-left">
+ <li class="active">Inspect Certificate</li>
+ </ol>
+ <div class="clearfix"></div>
+ </div>
+ <div class="x_content">
+ <ul class="nav nav-tabs" role="navlist">
+ <li role="presentation" ng-class="{active: navState === 0}">
+ <a data-toggle="tab" ng-click="updateState(0)">Upload</a>
+ </li>
+ <li role="presentation" ng-class="{active: navState === 1,
disabled: loadCert === ''}">
+ <a data-toggle="tab" ng-click="updateState(1)">Processed</a>
+ </li>
+ </ul>
+ <br />
+ <div class="tab-content">
+ <div class="tab-pane" role="tabpanel" ng-class="{show: navState
=== 0}">
+ <div>
+ <textarea id="fileContent" name="fileContent"
ng-model="inputCert" rows="25" cols="25" class="form-control"
required></textarea>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-success"
+ ng-disabled="inputCert === ''"
ng-click="load()">Load</button>
+ </div>
+ </div>
+ <div class="tab-pane" role="tabpanel" ng-class="{show: navState
=== 1}">
+ <cert-viewer-controller ng-if="loadCert !== ''"
chain="{{loadCert}}"></cert-viewer-controller>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/traffic_portal/app/src/common/modules/form/ssl/index.js
b/traffic_portal/app/src/common/modules/form/ssl/index.js
new file mode 100644
index 0000000000..df8e0305ff
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/form/ssl/index.js
@@ -0,0 +1,16 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+module.exports = angular.module("trafficPortal.form.ssl", [])
+ .controller("CertInspectController",
require("./CertInspectController"));
diff --git
a/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
b/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
index d14e3e5a43..88f27e2492 100644
--- a/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
+++ b/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
@@ -68,6 +68,7 @@ under the License.
<ul class="nav child_menu" style="display: none">
<li class="side-menu-category-item"
ng-if="hasCapability('jobs-read')" ng-class="{'current-page':
isState('trafficPortal.private.jobs')}"><a href="/#!/jobs">Invalidate
Content</a></li>
<li class="side-menu-category-item"
ng-if="hasCapability('iso-generate')" ng-class="{'current-page':
isState('trafficPortal.private.iso')}"><a href="/#!/iso">Generate ISO</a></li>
+ <li class="side-menu-category-item"
ng-class="{'current-page': isState('trafficPortal.private.ssl')}"><a
href="/#!/inspect-cert">Inspect Cert</a></li>
</ul>
</li>
<li class="side-menu-category"><a
href="javascript:void(0);"><i class="fa fa-sm fa-chevron-right"></i> User
Admin</a>
diff --git a/traffic_portal/app/src/common/modules/ssl/CertAuthorController.js
b/traffic_portal/app/src/common/modules/ssl/CertAuthorController.js
new file mode 100644
index 0000000000..bf1129a305
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/CertAuthorController.js
@@ -0,0 +1,36 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/** @typedef { import('./CertViewer').Certs } Certs */
+
+let CertAuthorController = function ($scope) {
+ /** @typedef Certs.Author */
+ this.author = {};
+ /** @typedef string */
+ this.authorType = "";
+ this.show = true;
+}
+
+angular.module("trafficPortal.ssl").component("certAuthorController", {
+ templateUrl: "common/modules/ssl/cert-author.tpl.html",
+ controller: CertAuthorController,
+ bindings: {
+ author: "<",
+ authorType: "@"
+ }
+});
+
+CertAuthorController.$inject = ["$scope"];
+module.exports = CertAuthorController;
diff --git a/traffic_portal/app/src/common/modules/ssl/CertViewer.d.ts
b/traffic_portal/app/src/common/modules/ssl/CertViewer.d.ts
new file mode 100644
index 0000000000..655a94ea0d
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/CertViewer.d.ts
@@ -0,0 +1,44 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+import * as forge from "node-forge";
+
+export namespace Certs {
+ type CertType = "Root" | "Client" | "Intermediate" | "Unknown" |
"Error";
+ type CertOrder = "Client -> Root" | "Root -> Client" | "Unknown" |
"Single";
+
+ /**
+ * Author contains the information about an author from a cert
issuer/subject
+ */
+ export interface Author {
+ countryName?: string | undefined;
+ stateOrProvince?: string | undefined;
+ localityName?: string | undefined;
+ orgName?: string | undefined;
+ orgUnit?: string | undefined;
+ commonName: string;
+ }
+
+ export interface Certificate extends forge.pki.Certificate {
+ issuerParsed: Author;
+ subjectParsed: Author;
+ type: CertType;
+ parseError: boolean;
+ sha1: forge.Hex;
+ sha256: forge.Hex;
+ oidName: string;
+ hidden: boolean;
+ miscHidden: boolean;
+ validityHidden: boolean;
+ }
+}
diff --git a/traffic_portal/app/src/common/modules/ssl/CertViewerController.js
b/traffic_portal/app/src/common/modules/ssl/CertViewerController.js
new file mode 100644
index 0000000000..5e36fa3c44
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/CertViewerController.js
@@ -0,0 +1,200 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/** @typedef { import('./CertViewer').Certs } Certs */
+
+let CertViewerController = function ($scope) {
+ /** @typedef Certs.Certificate[] */
+ this.certChain = [];
+ /** @typedef Certs.CertOrder */
+ this.certOrder = "";
+ /** @typedef string */
+ this.chain = "";
+
+ /** @type Certs.Certificate */
+ this.nullCert = window.forge.pki.createCertificate();
+ this.nullCert.type = "Error";
+ this.nullCert.parseError = true;
+
+ this.$onChanges = function() {
+ if(this.chain === "") {
+ return;
+ }
+ this.chain = this.chain.replace(/\r\n/g, "\n");
+ const parts = this.chain.split("-\n-");
+ const certs = new Array(parts.length);
+ for (let i = 1; i < parts.length; ++i) {
+ parts[i - 1] += "-";
+ parts[i] = `-${parts[i]}`;
+ certs[i - 1] = this.newCert(parts[i - 1]);
+ }
+ certs[certs.length - 1] = this.newCert(parts[parts.length - 1]);
+ const assignExtraInfo = (c, i) => {
+ if (c.parseError) {
+ return;
+ }
+ if (i === 0) {
+ c.type = "Root";
+ } else if (i === certs.length - 1) {
+ c.type = "Client";
+ } else {
+ c.type = "Intermediate";
+ }
+ c.sha1 = this.pkiCertToSHA1(c);
+ c.sha256 = this.pkiCertToSHA256(c);
+ c.parsedIssuer =
this.processAttributes(c.issuer.attributes);
+ c.parsedSubject =
this.processAttributes(c.subject.attributes);
+ c.oidName = this.oidToName(c.signatureOid);
+ };
+ const chain = this.reOrderRootFirst(certs);
+ chain.forEach(assignExtraInfo);
+ this.certChain = chain;
+ }
+
+ /**
+ * Converts a given oid to it's human-readable name
+ */
+ this.oidToName = function(oid) {
+ if (oid in window.forge.pki.oids) {
+ return window.forge.pki.oids[oid];
+ }
+ return "";
+ }
+
+ /**
+ * processAttributes converts attributes into an author
+ */
+ this.processAttributes = function(attrs) {
+ /** @typedef Certs.Author */
+ const a = {commonName: ""};
+ for (const attr of attrs) {
+ if (attr.name && attr.value) {
+ if (typeof attr.value !== "string") {
+ console.warn(`Unknown attribute value
${attr.value}`);
+ continue;
+ }
+ switch (attr.name) {
+ case "commonName":
+ a.commonName = attr.value;
+ break;
+ case "countryName":
+ a.countryName = attr.value;
+ break;
+ case "stateOrProvinceName":
+ a.stateOrProvince = attr.value;
+ break;
+ case "localityName":
+ a.localityName = attr.value;
+ break;
+ case "organizationName":
+ a.orgName = attr.value;
+ break;
+ case "organizationUnitName":
+ a.orgUnit = attr.value;
+ break;
+ }
+ }
+ }
+ return a;
+ }
+
+ /**
+ * pkiCertToSHA1 calculates the sha 1 of a cert
+ */
+ this.pkiCertToSHA1 = function (cert) {
+ const md = window.forge.md.sha1.create();
+
md.update(forge.asn1.toDer(window.forge.pki.certificateToAsn1(cert)).getBytes());
+ return md.digest().toHex();
+ }
+
+ /**
+ * pkiCertToSHA256 calculates the sha 256 of a cert
+ */
+ this.pkiCertToSHA256 = function (cert) {
+ const md = forge.md.sha256.create();
+
md.update(forge.asn1.toDer(window.forge.pki.certificateToAsn1(cert)).getBytes());
+ return md.digest().toHex();
+ }
+
+ /**
+ * newCert creates a cert from an input string.
+ */
+ this.newCert = function (input) {
+ try {
+ return forge.pki.certificateFromPem(input);
+ } catch (e) {
+ console.error(`ran into issue creating certificate from
input ${input}`, e);
+ return this.nullCert;
+ }
+ }
+
+ /**
+ * reOrderRootFirst sorts a cert chain with the root being first if
possible.
+ */
+ this.reOrderRootFirst = function (certs) {
+ let rootFirst = false;
+ let invalid = false;
+ for (let i = 1; i < certs.length; ++i) {
+ const first = certs[i - 1];
+ const next = certs[i];
+ if (first.parseError) {
+ invalid = true;
+ continue;
+ } else if (next.parseError) {
+ invalid = true;
+ continue;
+ }
+ if (first.issued(next)) {
+ rootFirst = true;
+ } else if (next.issued(first)) {
+ rootFirst = false;
+ } else {
+ invalid = true;
+ console.error(`Cert chain is invalid, cert ${i
- 1} and ${i} are not related`);
+ }
+ }
+
+ if (certs.length === 1) {
+ if (certs[0].parseError) {
+ invalid = true;
+ } else {
+ this.certOrder = "Single";
+ return certs;
+ }
+ }
+ if (invalid) {
+ this.certOrder = "Unknown";
+ return certs;
+ }
+
+ if (rootFirst) {
+ this.certOrder = "Root -> Client";
+ return certs;
+ }
+ this.certOrder = "Client -> Root";
+ certs = certs.reverse();
+ return certs;
+ }
+}
+
+angular.module("trafficPortal.ssl").component("certViewerController", {
+ templateUrl: "common/modules/ssl/cert-view.tpl.html",
+ controller: CertViewerController,
+ bindings: {
+ chain: "@"
+ }
+});
+
+CertViewerController.$inject = ["$scope"];
+module.exports = CertViewerController;
diff --git a/traffic_portal/app/src/common/modules/ssl/_ssl.scss
b/traffic_portal/app/src/common/modules/ssl/_ssl.scss
new file mode 100644
index 0000000000..a5bf059d77
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/_ssl.scss
@@ -0,0 +1,28 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+fieldset {
+ fieldset legend {
+ font-size: 16px !important;
+ }
+ legend {
+ font-size: 18px !important;
+ font-weight: bold;
+
+ .fa {
+ float: right;
+ margin-right: 10px;
+ }
+ }
+}
diff --git a/traffic_portal/app/src/common/modules/ssl/cert-author.tpl.html
b/traffic_portal/app/src/common/modules/ssl/cert-author.tpl.html
new file mode 100644
index 0000000000..01e53455ba
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/cert-author.tpl.html
@@ -0,0 +1,66 @@
+<!--
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+<div>
+ <fieldset>
+ <legend ng-click="$ctrl.show = !$ctrl.show">
+ {{$ctrl.authorType}}
+ <i class="fa" ng-class="$ctrl.show ? 'fa-caret-down' :
'fa-caret-up'"></i>
+ </legend>
+ <div ng-show="$ctrl.show">
+ <div class="form-group">
+ <label for="commonName" class="control-label col-md-2 col-sm-2
col-xs-12">Common Name</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="commonName" id="commonName"
type="text" class="form-control"
+ ng-model="$ctrl.author.commonName"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="countryName" class="control-label col-md-2
col-sm-2 col-xs-12">Country Name</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="countryName" id="countryName"
type="text" class="form-control"
+ ng-model="$ctrl.author.countryName"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="stateOrProvince" class="control-label col-md-2
col-sm-2 col-xs-12">State/Province</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="stateOrProvince"
id="stateOrProvince" type="text" class="form-control"
+ ng-model="$ctrl.author.stateOrProvince"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="locality" class="control-label col-md-2 col-sm-2
col-xs-12">Locality</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="locality" id="locality" type="text"
class="form-control"
+ ng-model="$ctrl.author.localityName"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="orgName" class="control-label col-md-2 col-sm-2
col-xs-12">Organization</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="orgName" id="orgName" type="text"
class="form-control"
+ ng-model="$ctrl.author.orgName"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="orgUnit" class="control-label col-md-2 col-sm-2
col-xs-12">Organization Unit</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="orgUnit" id="orgUnit" type="text"
class="form-control"
+ ng-model="$ctrl.author.orgUnit"/>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+</div>
diff --git a/traffic_portal/app/src/common/modules/ssl/cert-view.tpl.html
b/traffic_portal/app/src/common/modules/ssl/cert-view.tpl.html
new file mode 100644
index 0000000000..307f08f100
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/cert-view.tpl.html
@@ -0,0 +1,99 @@
+<!--
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<form name="certViewerForm" class="form-horizontal form-label-left" novalidate>
+ <div class="form-group">
+ <label for="certOrder" class="control-label col-md-2 col-sm-2
col-xs-12">Detected Order</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="certOrder" id="certOrder" type="text"
class="form-control"
+ ng-model="$ctrl.certOrder"/>
+ </div>
+ </div>
+ <hr/>
+ <fieldset ng-repeat="cert in $ctrl.certChain">
+ <legend ng-click="cert.hidden = !cert.hidden">
+ {{cert.type}}
+ <i class="fa" ng-class="cert.hidden ? 'fa-caret-up' :
'fa-caret-down'"></i>
+ </legend>
+ <div ng-show="!cert.hidden">
+ <cert-author-controller author-type="Issuer"
author="cert.parsedIssuer"></cert-author-controller>
+ <cert-author-controller author-type="Subject"
author="cert.parsedSubject"></cert-author-controller>
+ <fieldset>
+ <legend ng-click="cert.validityHidden = !cert.validityHidden">
+ Validity
+ <i class="fa" ng-class="cert.validityHidden ?
'fa-caret-up' : 'fa-caret-down'"></i>
+ </legend>
+ <div ng-show="!cert.validityHidden">
+ <div class="form-group">
+ <label for="validBefore" class="control-label col-md-2
col-sm-2 col-xs-12">Not Valid Before</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="validBefore"
id="validBefore" type="text" class="form-control"
+ ng-model="cert.validity.notBefore"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="validAfter" class="control-label col-md-2
col-sm-2 col-xs-12">Not Valid After</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="validAfter" id="validAfter"
type="text" class="form-control"
+ ng-model="cert.validity.notAfter"/>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend ng-click="cert.miscHidden = !cert.miscHidden">
+ Misc
+ <i class="fa" ng-class="cert.miscHidden ? 'fa-caret-up' :
'fa-caret-down'"></i>
+ </legend>
+ <div ng-show="!cert.miscHidden">
+ <div class="form-group">
+ <label for="sigType" class="control-label col-md-2
col-sm-2 col-xs-12">Signature Algorithm</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="sigType" id="sigType"
type="text" class="form-control"
+ ng-model="cert.oidName"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="version" class="control-label col-md-2
col-sm-2 col-xs-12">Version</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="version" id="version"
type="text" class="form-control"
+ ng-model="cert.version"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="serial" class="control-label col-md-2
col-sm-2 col-xs-12">Serial Number</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="serial" id="serial"
type="text" class="form-control"
+ ng-model="cert.serialNumber"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="sha1" class="control-label col-md-2
col-sm-2 col-xs-12">SHA-1</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="sha1" id="sha1" type="text"
class="form-control" ng-model="cert.sha1"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="sha256" class="control-label col-md-2
col-sm-2 col-xs-12">SHA-256</label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input readonly name="sha256" id="sha256"
type="text" class="form-control"
+ ng-model="cert.sha256"/>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </fieldset>
+</form>
diff --git a/traffic_portal/app/src/common/modules/ssl/index.js
b/traffic_portal/app/src/common/modules/ssl/index.js
new file mode 100644
index 0000000000..91524c433e
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/ssl/index.js
@@ -0,0 +1,17 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+module.exports = angular.module("trafficPortal.ssl", [])
+ .controller("CertViewerController", require("./CertViewerController"))
+ .controller("CertAuthorController", require("./CertAuthorController"));
diff --git a/traffic_portal/app/src/modules/private/ssl/index.js
b/traffic_portal/app/src/modules/private/ssl/index.js
new file mode 100644
index 0000000000..3f6c8bfdf5
--- /dev/null
+++ b/traffic_portal/app/src/modules/private/ssl/index.js
@@ -0,0 +1,28 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+module.exports = angular.module("trafficPortal.private.ssl", [])
+ .config(function($stateProvider, $urlRouterProvider) {
+ $stateProvider
+ .state("trafficPortal.private.ssl", {
+ url: "inspect-cert",
+ views: {
+ privateContent: {
+ templateUrl:
"common/modules/form/ssl/cert-inspect.tpl.html",
+ controller:
"CertInspectController",
+ }
+ }
+ });
+ $urlRouterProvider.otherwise("/");
+ });
diff --git a/traffic_portal/app/src/modules/private/ssl/inspect-cert.tpl.html
b/traffic_portal/app/src/modules/private/ssl/inspect-cert.tpl.html
new file mode 100644
index 0000000000..059211e369
--- /dev/null
+++ b/traffic_portal/app/src/modules/private/ssl/inspect-cert.tpl.html
@@ -0,0 +1,18 @@
+<!--
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<div id="inspectCertContainer">
+ <div ui-view="certInspect"></div>
+</div>
diff --git a/traffic_portal/app/src/scripts/shared-libs.js
b/traffic_portal/app/src/scripts/shared-libs.js
index 3a362d8348..d97d6928b0 100644
--- a/traffic_portal/app/src/scripts/shared-libs.js
+++ b/traffic_portal/app/src/scripts/shared-libs.js
@@ -52,3 +52,6 @@ require('jquery-flot-stack');
require('jquery-flot-time');
require('jquery-flot-tooltip');
require('jquery-flot-axislabels');
+
+/** @typedef { import("node-forge") } forge */
+window.forge = require("node-forge");
diff --git a/traffic_portal/app/src/styles/main.scss
b/traffic_portal/app/src/styles/main.scss
index c4f0e6aab4..219f6cdf83 100644
--- a/traffic_portal/app/src/styles/main.scss
+++ b/traffic_portal/app/src/styles/main.scss
@@ -32,8 +32,10 @@ $fa-font-path: "../assets/fonts";
@import "../common/modules/header/header";
@import "../common/modules/form/cacheGroup/form.cacheGroup";
@import "../common/modules/form/form";
+@import "../common/modules/form/ssl/inspect-ssl";
@import "../common/modules/locks/locks";
@import "../common/modules/navigation/navigation";
+@import "../common/modules/ssl/ssl";
@import "../common/modules/table/table";
@import "../common/modules/table/parameters/table.parameters";
@import "../common/modules/release/release";
diff --git a/traffic_portal/package-lock.json b/traffic_portal/package-lock.json
index 59413f620b..bcadf4a55b 100644
--- a/traffic_portal/package-lock.json
+++ b/traffic_portal/package-lock.json
@@ -23,12 +23,14 @@
"flot": "2.3.2",
"font-awesome": "4.7.0",
"jquery": "3.6.1",
- "jquery.flot.tooltip": "0.9.0"
+ "jquery.flot.tooltip": "0.9.0",
+ "node-forge": "^1.3.1"
},
"devDependencies": {
"@types/angular": "^1.8.4",
"@types/jquery": "^3.5.14",
"@types/moment": "^2.13.0",
+ "@types/node-forge": "^1.3.2",
"angular-mocks": "1.8.3",
"browserify": "16.5.1",
"connect-livereload": "0.6.1",
@@ -102,6 +104,21 @@
"moment": "*"
}
},
+ "node_modules/@types/node": {
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz",
+ "integrity":
"sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==",
+ "dev": true
+ },
+ "node_modules/@types/node-forge": {
+ "version": "1.3.2",
+ "resolved":
"https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.2.tgz",
+ "integrity":
"sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/sizzle": {
"version": "2.3.3",
"resolved":
"https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
@@ -6034,6 +6051,14 @@
"integrity":
"sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
+ "node_modules/node-forge": {
+ "version": "1.3.1",
+ "resolved":
"https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity":
"sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
"node_modules/nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@@ -7179,12 +7204,6 @@
"@types/node": "*"
}
},
- "node_modules/socket.io/node_modules/@types/node": {
- "version": "18.11.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity":
"sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
- "dev": true
- },
"node_modules/socket.io/node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
@@ -8427,6 +8446,21 @@
"moment": "*"
}
},
+ "@types/node": {
+ "version": "20.4.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz",
+ "integrity":
"sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==",
+ "dev": true
+ },
+ "@types/node-forge": {
+ "version": "1.3.2",
+ "resolved":
"https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.2.tgz",
+ "integrity":
"sha512-TzX3ahoi9xbmaoT58smrBu7oa6dQXb/+PTNCslZyD/55tlJ/osofIMClzZsoo6buDFrg7e4DvVGkZqVgv6OLxw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/sizzle": {
"version": "2.3.3",
"resolved":
"https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
@@ -13204,6 +13238,11 @@
"integrity":
"sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
+ "node-forge": {
+ "version": "1.3.1",
+ "resolved":
"https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity":
"sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
+ },
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@@ -14144,12 +14183,6 @@
"@types/node": "*"
}
},
- "@types/node": {
- "version": "18.11.18",
- "resolved":
"https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity":
"sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
- "dev": true
- },
"base64id": {
"version": "2.0.0",
"resolved":
"https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
diff --git a/traffic_portal/package.json b/traffic_portal/package.json
index 429ac89c82..407a1f0463 100644
--- a/traffic_portal/package.json
+++ b/traffic_portal/package.json
@@ -18,6 +18,7 @@
"@types/angular": "^1.8.4",
"@types/jquery": "^3.5.14",
"@types/moment": "^2.13.0",
+ "@types/node-forge": "^1.3.2",
"angular-mocks": "1.8.3",
"browserify": "16.5.1",
"connect-livereload": "0.6.1",
@@ -63,6 +64,7 @@
"flot": "2.3.2",
"font-awesome": "4.7.0",
"jquery": "3.6.1",
- "jquery.flot.tooltip": "0.9.0"
+ "jquery.flot.tooltip": "0.9.0",
+ "node-forge": "^1.3.1"
}
}