├── README.md ├── static ├── model.png ├── style.css ├── themes │ └── default │ │ └── assets │ │ ├── fonts │ │ ├── icons.eot │ │ ├── icons.otf │ │ ├── icons.ttf │ │ ├── icons.woff │ │ └── icons.woff2 │ │ └── images │ │ └── flags.png └── jquery.min.js ├── templates ├── model.png ├── index.html ├── reports.html ├── assessments.html ├── risk_acceptance.html ├── risk_report.html ├── controls_soa.html ├── layout.html ├── alignment.html ├── about.html ├── deliverables.html ├── report_process.html └── analyse_process.html ├── Dockerfile ├── LICENSE ├── assessments ├── deliverables.json ├── schema.json ├── data.json └── control_library.json └── openisms.py /README.md: -------------------------------------------------------------------------------- 1 | # openisms 2 | See https://github.com/Asbaek/openisms/wiki 3 | -------------------------------------------------------------------------------- /static/model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/model.png -------------------------------------------------------------------------------- /templates/model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/templates/model.png -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | .pusher { 2 | margin-bottom: 20px; 3 | } 4 | 5 | .site-menu { 6 | margin-bottom: 20px !important; 7 | } 8 | -------------------------------------------------------------------------------- /static/themes/default/assets/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/fonts/icons.eot -------------------------------------------------------------------------------- /static/themes/default/assets/fonts/icons.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/fonts/icons.otf -------------------------------------------------------------------------------- /static/themes/default/assets/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/fonts/icons.ttf -------------------------------------------------------------------------------- /static/themes/default/assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/fonts/icons.woff -------------------------------------------------------------------------------- /static/themes/default/assets/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/fonts/icons.woff2 -------------------------------------------------------------------------------- /static/themes/default/assets/images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asbaek/openisms/HEAD/static/themes/default/assets/images/flags.png -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 | Welcome to openISMS.
5 |
6 | Visit About for an overview. 7 | {% endblock %} 8 | 9 | -------------------------------------------------------------------------------- /templates/reports.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

Reports for management

5 | 8 | 9 |

Reports for specialists

10 | 14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # To build and run 2 | # docker build -t openisms . 3 | # docker run -it --rm -p 5000:5000 -v `pwd`/assessments:/srv/openisms/assessments openisms 4 | # 5 | # While developing 6 | # docker run -it --rm -p 5000:5000 -v `pwd`:/srv/openisms -e DEBUG=true openisms 7 | 8 | FROM ubuntu:latest 9 | 10 | RUN apt-get update && \ 11 | apt-get dist-upgrade -y && \ 12 | apt-get install -y python-pip && \ 13 | pip install flask 14 | RUN mkdir /srv/openisms 15 | 16 | ADD . /srv/openisms/ 17 | 18 | WORKDIR /srv/openisms 19 | EXPOSE 5000 20 | VOLUME ["assessments"] 21 | 22 | ENV HOSTNAME=0.0.0.0 23 | ENTRYPOINT ["/usr/bin/python", "openisms.py"] 24 | -------------------------------------------------------------------------------- /templates/assessments.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

Processes

5 |
6 | {% for process in process_table|sort(attribute='process_name') %} 7 |
8 |
9 | 10 | 11 |
12 |
13 | {% endfor %} 14 |
15 | 16 | 17 | 18 |
19 |
20 | 22 | 23 | {% endblock %} 24 | 25 | -------------------------------------------------------------------------------- /templates/risk_acceptance.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

Risks

5 | This list show all risks with action "Retention" (or Accept) in OpenISMS. 6 | 7 | 8 | 9 | 10 | 11 | {% for threat in threat_table|sort(attribute='risk_score', reverse = True) %} 12 | {% if threat.threat_action=="Retention" %} 13 | 25 | {% endif %} 26 | {% endfor %} 27 | 28 |
Risk NameRisk Score (0-10)Asset OwnerSufficient mitigation implemented?Selected Action Type
14 | {{threat.asset_name}} - {{threat.threat_name}} 15 | 16 | {{threat.risk_score}} 17 | 18 | {{threat.asset_owner}} 19 | 20 | {% if threat.threat_action_executed=="True" %} Yes {% endif %} 21 | {% if threat.threat_action_executed=="False" %} No {% endif %} 22 | 23 | {{threat.threat_action}} 24 |
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /templates/risk_report.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

All Risks

5 | This list show all risks recorded in OpenISMS. 6 | 7 | 8 | 9 | 10 | 11 | {% for threat in threat_table|sort(attribute='risk_score', reverse = True) %} 12 | 29 | 30 | {% endfor %} 31 | 32 |
Risk NumberRisk NameProcess NameRisk Score
(0-10)
Asset OwnerSufficient mitigation implemented?
13 |
14 | {{ loop.index }} 15 |
16 |
17 | {{threat.asset_name}} - {{threat.threat_name}} 18 | 19 | {{threat.process_name}} 20 | 21 | {{threat.risk_score}} 22 | 23 | {{threat.asset_owner}} 24 | 25 | {% if threat.threat_action_executed=="True" %} Yes {% endif %} 26 | {% if threat.threat_action_executed=="False" %} No {% endif %} 27 | {% if threat.threat_action_executed=="" %} Not assessed {% endif %} 28 |
33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /templates/controls_soa.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

All Risks

5 | This list show all risks recorded in OpenISMS. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for control in control_table %} 19 | 20 | 21 | 22 | 31 | 40 | 41 | 50 | 51 | {% endfor %} 52 | 53 |
Control IDControl NameInformation to coverContainers to coverTimes usedAssociated deliverables
{{control.control_id}}{{control.control_name}} 23 |
    24 | {% for asset in control.control_assets %} 25 |
  • {{asset}}
  • 26 | {% else %} 27 |
  • None
  • 28 | {% endfor %} 29 |
30 |
32 |
    33 | {% for container in control.control_containers %} 34 |
  • {{container}}
  • 35 | {% else %} 36 |
  • None
  • 37 | {% endfor %} 38 |
39 |
{{control.control_count}} 42 |
    43 | {% for deliverable_name in control.deliverable_names %} 44 |
  • {{deliverable_name}}
  • 45 | {% else %} 46 |
  • None
  • 47 | {% endfor %} 48 |
49 |
54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | NORDUnet BSD Software License 2 | Copyright (c) 2011, NORDUnet A/S 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | Neither the name of the NORDUnet nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenISMS 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 32 | 33 |
34 |

OpenISMS

35 | 36 | {% block body %}{% endblock %} 37 |
38 |
39 | 40 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /templates/alignment.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 | {# EXPLAINATION: WHAT IS IMPACT, PRIORITY, LEVELS USED FOR AND HOW IS IT CHANGED #} 5 | 6 |

Alignment

7 | Important: You should update values shown on this page to fit your organisation.

8 | 9 | Key priorities made by your organisation is outlined on this page. This must be done to ensure alignment between your organisation and your risk management efforts. The prioities will affect how all your risks are prioritised, so chose them carefully. 10 | 11 | Impact priority is the organisations priorities of different risk types. Changing the priority will change how threats are scored and prioritised. Higher priority means higher weight in the risk score.

12 | 13 | Impact levels are used when assessing threats. Impact levels describes the differences between low, medium, high and critical levels.

14 | 15 | NOTE: You change the impact priorities and levels by manually editing the impact_description section of the assessments/data.json file.

16 | 17 | {# SHOW IMPACT PRIORITIES FROM data.json file #} 18 |

Impact Priorities

19 | 20 | 21 | {% set numbers=["1","2","3","4","5"] %} 22 | {% for number in numbers %} 23 | {% for impact in global_impact_details %} 24 | {% if number==impact.priority %} 25 | 26 | 27 | {% endif %} 28 | {% endfor %} 29 | {% endfor %} 30 |
Organisations priorityImpact description
{{ impact.priority }}
{{ impact.description }}
31 | 32 | {# SHOW INDIVIDUAL IMPACT LEVELS #} 33 |

Impact Levels

34 | 35 | 36 | {% for impact in global_impact_details %} 37 | 38 | 39 | 40 | 41 | {% endfor %} 42 |
Impact descriptionImpact levelLevel description
{{ impact.description }} Low {{ impact.low }}
{{ impact.description }} Medium {{ impact.medium }}
{{ impact.description }} High {{ impact.high }}
{{ impact.description }} Critical {{ impact.critical }}
43 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

What is OpenISMS?

5 | OpenISMS is a tool for information security management.
6 | You can use OpenISMS to perform structured risk assessments.
7 | When you have some risk assessments, you can create various reports.
8 | It also allows you to track security document deliverables.
9 | 10 |

What is the Data Model?

11 | OpenISMS is inspired the security model OCTAVE Allegro.
12 | This model fulfills the requirement for risk assessment from many different security standards.
13 | OpenISMS is build around the fundamental risk concepts described below.
14 | 15 | 16 |

What is a Risk?

17 | Risk is potential harm to your organization.
18 | An Information Security Risk contains these elements: 19 | 25 | Real Life Example:
26 | You have a vase of value to you (an asset).
27 | The neigbours son has a football (threat).
28 | In the summer you open your windows (vulnerability).
29 | You instruct the kid not to play football up against your walls or you move the vase to a safer spot (control).
30 |
31 | Technical Example:
32 | Your organisation runs a popular blog (blog posts are critical information).
33 | Some people do not like the blog content and run DDoS attacks against it (threats)
34 | Your webserver is an easy target on the internet and everybody can attack it (vulnerability).
35 | You ask your ISP to ratelimit everything else than webtraffic (control).
36 | 37 | 38 |

What is a Risk Assessment?

39 | Risk assessment consists of two parts.
40 | Risk analysis to understand the risks to your organisation and a decision on how to threat that risk
41 | OpenISMS can be used to do risk assessment. 42 | 43 |

How do I Perform a Risk Assessment?

44 | Take a look at the data model of OpenISMS on this page.
45 | You perform a risk assessment by describing each element of the model.
46 | By selecting "Assessment" in the menu, you can find forms to assist this process. 47 | 48 | {% endblock %} 49 | 50 | -------------------------------------------------------------------------------- /templates/deliverables.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Documents

4 | This page is an inventory of documents used to implement the ISMS.
5 | NOTE: You can assess and add documents in the documents section of the assessments/deliverables.json file.
6 |
7 |

Maturity definitions

8 | 9 | 10 | 11 | 12 | 13 | {% for i in ["0","1","2","3","4","5"] %} 14 | {% for element, description in deliverable_maturity.iteritems() %} 15 | {% if i == element %} 16 | 17 | 18 | 19 | 20 | {% endif %} 21 | {% endfor %} 22 | {% endfor %} 23 |
Maturity levelDescription
{{element}}{{description}}
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {% for delivery in deliverables_table %} 37 | 38 | 39 | 40 | 41 | 47 | 58 | 69 | 71 | 72 | 73 | {% endfor %} 74 |
Delivery nameTypeLinkMaturity currentMaturity plannedMaturity progressISO referencesNumber of references from SOA
{{ delivery.name }} {{ delivery.type}} 42 | 43 | 44 | 45 | 46 | 48 |
49 | 55 | 56 |
57 |
59 |
60 | 66 | 67 |
68 |
70 | {% for control in delivery.controls %} {{ control }}
{% endfor %}
{{ delivery.count }}
75 | 76 | 77 | {% endblock %} 78 | -------------------------------------------------------------------------------- /templates/report_process.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 | {# FORM TO UPDATE PROCESS DETAILS #} 5 | {% for process in process_table %} {#loop ends at end of template!#} 6 | 7 |

Risk Report for {{process.process_name}}

8 |

Process description

9 | {{process.process_description}} 10 |
11 |
12 | 13 |
14 |

Critical Information

15 | {# FORM TO SELECT ASSET TO UPDATE, ADD OR DELETE #} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for asset in asset_table %} 30 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | {% endfor %} 41 |
Critical Information NameDescriptionOwnerConfidentialIntegrity critical Availability criticalBackup frequency
(RPO)
Lowest acceptable recovery time
(RTO)
{{asset.asset_name}}{{asset.asset_description}}{{asset.asset_owner}}{% if asset.asset_criticality_c == "True" %}Yes{% else %}No{% endif %} 35 | {% if asset.asset_criticality_i == "True" %}Yes{% else %}No{% endif %} 36 | {% if asset.asset_criticality_a == "True" %}Yes{% else %}No{% endif %} 37 | {{asset.asset_rpo_days}} {{asset.asset_rto_days}}
42 |
43 |
44 | 45 | {# Threat form #} 46 |
47 |

Risk Environment

48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {% for asset in asset_table %} {# ends at end of template!#} 58 | {% for threat in threat_table|sort(attribute='risk_score', reverse = True ) %} 59 | {% if threat.asset_id == asset.asset_id %} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {% endif %} 68 | {% endfor %} 69 | {% endfor %} 70 |
RiskRisk Score assuming no controls
(0-10)
Threat descriptionTreatment decision assuming no controlsAcceptable Treatment established today?
{{ asset.asset_name }} - {{ threat.threat_name }} {{ threat.risk_score }} {{ threat.threat_description }} {{ threat.threat_action }} {% if threat.threat_action_executed == "True" %}Yes{% else %}No{% endif %}
71 |
72 |
73 | 74 |
75 |

Control selection

76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | {% for asset in asset_table %} {# ends at end of template!#} 84 | {% for threat in threat_table %} 85 | {% for container in threat.containers|sort(attribute='container_name') %} 86 | {% if threat.asset_id == asset.asset_id %} 87 | 88 | 89 | 90 | 91 | 98 | 99 | {% endfor %} 100 | {% endfor %} 101 |
ContainerCritical InformationThreatControls
{{container.container_name}}{{asset.asset_name}}{{threat.threat_name}} 92 | {% for control in container.container_controls|sort(attribute='control_id') %} 93 | {{control.control_id}} {{control.control_name}}
94 | {% endfor %} 95 | {% endif %} 96 | {% endfor %} 97 |
102 |
103 | 104 | {% endfor %} 105 | 106 |
107 |
108 |

Signatures

109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | {% for asset in asset_table %} 120 | 121 | 122 | 123 | {% endfor %} 124 | 125 |
126 | 127 | {% endblock %} 128 | -------------------------------------------------------------------------------- /assessments/deliverables.json: -------------------------------------------------------------------------------- 1 | { 2 | "deliverables": [ 3 | { 4 | "maturity_current": "0", 5 | "name": "Organisation and ISMS Scope", 6 | "maturity_planned": "3", 7 | "link": "Draft", 8 | "controls": [ 9 | "Clause 4.1", 10 | "Clause 4.2", 11 | "Clause 4.3"], 12 | "_id": "D0001", 13 | "type": "Mandatory Document" 14 | }, 15 | { 16 | "maturity_current": "0", 17 | "name": "Information Security Policy", 18 | "maturity_planned": "3", 19 | "link": "Draft", 20 | "controls": ["Clause 5.2"], 21 | "_id": "D0002", 22 | "type": "Mandatory Document" 23 | }, 24 | { 25 | "maturity_current": "0", 26 | "name": "Risk Assessment Method", 27 | "maturity_planned": "3", 28 | "link": "Draft", 29 | "controls": ["Clause 6.1.2"], 30 | "_id": "D0003", 31 | "type": "Mandatory Document" 32 | }, 33 | { 34 | "maturity_current": "0", 35 | "name": "Statement of Applicability", 36 | "maturity_planned": "3", 37 | "link": "Draft", 38 | "controls": ["Clause 6.1.3"], 39 | "_id": "D0003", 40 | "type": "Mandatory Document" 41 | }, 42 | { 43 | "maturity_current": "0", 44 | "name": "Risk Treatment Plan", 45 | "maturity_planned": "3", 46 | "link": "Draft", 47 | "controls": [ 48 | "Clause 6.1.3", 49 | "Clause 6.2" 50 | ], 51 | "_id": "D0004", 52 | "type": "Mandatory Document" 53 | }, 54 | { 55 | "maturity_current": "0", 56 | "name": "Information Security Objectives", 57 | "maturity_planned": "3", 58 | "link": "Draft", 59 | "controls": ["Clause 6.2"], 60 | "_id": "D0002", 61 | "type": "Mandatory Document" 62 | }, 63 | { 64 | "maturity_current": "0", 65 | "name": "Training, Education and Awareness Records", 66 | "maturity_planned": "3", 67 | "link": "Draft", 68 | "controls": ["Clause 7.2"], 69 | "_id": "D0002", 70 | "type": "Mandatory Records" 71 | }, 72 | { 73 | "maturity_current": "0", 74 | "name": "Risk Assessment Report", 75 | "maturity_planned": "3", 76 | "link": "Draft", 77 | "controls": ["Clause 8.2"], 78 | "_id": "D0002", 79 | "type": "Mandatory Document" 80 | }, 81 | { 82 | "maturity_current": "0", 83 | "name": "Security Performance and Measurement Results", 84 | "maturity_planned": "3", 85 | "link": "Draft", 86 | "controls": ["Clause 9.1"], 87 | "_id": "D0002", 88 | "type": "Mandatory Records" 89 | }, 90 | { 91 | "maturity_current": "0", 92 | "name": "Internal Audit Program", 93 | "maturity_planned": "3", 94 | "link": "Draft", 95 | "controls": ["Clause 9.2"], 96 | "_id": "D0002", 97 | "type": "Mandatory Records" 98 | }, 99 | { 100 | "maturity_current": "0", 101 | "name": "Internal Audit Results", 102 | "maturity_planned": "3", 103 | "link": "Draft", 104 | "controls": ["Clause 9.2"], 105 | "_id": "D0002", 106 | "type": "Mandatory Records" 107 | }, 108 | { 109 | "maturity_current": "0", 110 | "name": "Management Review Memos", 111 | "maturity_planned": "3", 112 | "link": "Draft", 113 | "controls": ["Clause 9.3"], 114 | "_id": "D0005", 115 | "type": "Mandatory Record" 116 | }, 117 | { 118 | "maturity_current": "0", 119 | "name": "Corrective Action Results", 120 | "maturity_planned": "3", 121 | "link": "Draft", 122 | "controls": ["Clause 10.1"], 123 | "_id": "D0005", 124 | "type": "Mandatory Record" 125 | }, 126 | { 127 | "maturity_current": "0", 128 | "name": "Security Roles and Responsibilities", 129 | "maturity_planned": "3", 130 | "link": "Draft", 131 | "controls": ["A.6.1.1"], 132 | "_id": "D0002", 133 | "type": "Mandatory Document" 134 | }, 135 | { 136 | "maturity_current": "0", 137 | "name": "Asset Inventory", 138 | "maturity_planned": "3", 139 | "link": "Draft", 140 | "controls": ["A.8.1.1"], 141 | "_id": "D0006", 142 | "type": "Mandatory Document" 143 | }, 144 | { 145 | "maturity_current": "0", 146 | "name": "Acceptable Use Policy", 147 | "maturity_planned": "3", 148 | "link": "Draft", 149 | "controls": ["A.8.1.3"], 150 | "_id": "D0006", 151 | "type": "Mandatory Document" 152 | }, 153 | { 154 | "maturity_current": "0", 155 | "name": "Access Control Policy", 156 | "maturity_planned": "3", 157 | "link": "Draft", 158 | "controls": ["A.9.1.1"], 159 | "_id": "D0006", 160 | "type": "Mandatory Document" 161 | }, 162 | { 163 | "maturity_current": "0", 164 | "name": "IT Operating Procedures", 165 | "maturity_planned": "3", 166 | "link": "Draft", 167 | "controls": ["A.12.1.1"], 168 | "_id": "D0006", 169 | "type": "Mandatory Document" 170 | }, 171 | { 172 | "maturity_current": "0", 173 | "name": "System Engineering Security Principles", 174 | "maturity_planned": "3", 175 | "link": "Draft", 176 | "controls": ["A.14.2.5"], 177 | "_id": "D0006", 178 | "type": "Mandatory Document" 179 | }, 180 | { 181 | "maturity_current": "0", 182 | "name": "Log Reviews", 183 | "maturity_planned": "3", 184 | "link": "Draft", 185 | "controls": ["A.12.4.1","A.12.4.3"], 186 | "_id": "D0005", 187 | "type": "Mandatory Record" 188 | }, 189 | { 190 | "maturity_current": "0", 191 | "name": "Supplier Relationship Security Policy", 192 | "maturity_planned": "3", 193 | "link": "Draft", 194 | "controls": ["A.15.1.1"], 195 | "_id": "D0006", 196 | "type": "Mandatory Document" 197 | }, 198 | { 199 | "maturity_current": "0", 200 | "name": "Security Incident Procedure", 201 | "maturity_planned": "3", 202 | "link": "Draft", 203 | "controls": ["A.16.1.5"], 204 | "_id": "D0006", 205 | "type": "Mandatory Document" 206 | }, 207 | { 208 | "maturity_current": "0", 209 | "name": "Security Business Continuity Procedures", 210 | "maturity_planned": "3", 211 | "link": "Draft", 212 | "controls": ["A.17.1.2"], 213 | "_id": "D0006", 214 | "type": "Mandatory Document" 215 | }, 216 | { 217 | "maturity_current": "0", 218 | "name": "Contractual and Regulatory Security Requirements", 219 | "maturity_planned": "3", 220 | "link": "Draft", 221 | "controls": ["A.18.1.1"], 222 | "_id": "D0006", 223 | "type": "Mandatory Document" 224 | } 225 | ], 226 | "document_types":[ 227 | "Mandatory Document", 228 | "Optional Document", 229 | "Mandatory Record", 230 | "Optional Record" 231 | ], 232 | "deliverable_maturity": { 233 | "0": "Non-existent. Absence of awareness and documentation", 234 | "1": "Initial. Awareness of need to study is present, but no documentation", 235 | "2": "Managed. Documentation exists and is being followed. Lack of training and standards. Rely on indviduals", 236 | "3": "Defined. Standardized and communicated documents exist. No detection of failure. Low level of sophistication in documents", 237 | "4": "Quantitavely managed. Compliance with document is monitored and measured. Action can be taken errors are detected. Good practice alignment and continual improvement is in place. Automation is lacking", 238 | "5": "Optimised. High level of automation. Process can be adjusted quickly to business needs." 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /assessments/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "processes": [ 3 | { 4 | "process_name": "", 5 | "process_id": "", 6 | "process_description": "", 7 | "process_business_unit":"" 8 | } 9 | ], 10 | "threats": [ 11 | { 12 | "threat_id": "", 13 | "impact_scores": [ 14 | { 15 | "score": "0", 16 | "type": "legal" 17 | }, 18 | { 19 | "score": "0", 20 | "type": "financial" 21 | }, 22 | { 23 | "score": "0", 24 | "type": "productivity" 25 | }, 26 | { 27 | "score": "0", 28 | "type": "reputational" 29 | }, 30 | { 31 | "score": "0", 32 | "type": "health" 33 | } 34 | ], 35 | "threat_description": "", 36 | "threat_action": "", 37 | "threat_action_rationale": "", 38 | "threat_name": "", 39 | "threat_action_executed": "", 40 | "threat_probability": "" 41 | } 42 | ], 43 | "assets": [ 44 | { 45 | "asset_id": "", 46 | "asset_rpo_days": "Not selected", 47 | "asset_criticality_i": "False", 48 | "asset_criticality_c": "False", 49 | "asset_description": "", 50 | "asset_criticality_a": "False", 51 | "asset_owner": "", 52 | "asset_name": "", 53 | "process_id": "", 54 | "asset_rto_days": "Not selected" 55 | } 56 | ], 57 | "global_impact_details": [ 58 | { 59 | "priority": "1", 60 | "medium": "Revokable damage to reputation and stakeholders confidence", 61 | "description": "Reputation and stakeholder confidence", 62 | "high": "Irrevokable damage to less important stakholders confidence", 63 | "critical": "Irrevokable damage to key stakholders confidence or public reputation", 64 | "low": "Minimal damage to reputation and stakeholder confidence", 65 | "type": "reputational" 66 | }, 67 | { 68 | "priority": "2", 69 | "medium": "Fines, non-frivolous lawsuits or investigations do not exceed 200.000 euro", 70 | "description": "Fines and legal penialties", 71 | "high": "Fines, non-frivolous lawsuits or investigations exceed 200.000 euro", 72 | "critical": "Public investigations of organisational practices is made", 73 | "low": "Fines, non-frivolous lawsuits or investigations do not exceed 50.000 euro", 74 | "type": "legal" 75 | }, 76 | { 77 | "priority": "3", 78 | "medium": "Yearly revenue reduction or one time loss of 50.000-200.000 euros", 79 | "description": "Financial", 80 | "high": "Yearly revenue reduction or one time loss of 200.000-500.000 euros", 81 | "critical": "Yearly revenue reduction or one time loss of more than 500.000 euros", 82 | "low": "Yearly revenue reduction or one time loss of less than 50.000 euros", 83 | "type": "financial" 84 | }, 85 | { 86 | "priority": "4", 87 | "medium": "Maximum 4 days of degrade in employee or customer health.", 88 | "description": "Health and safety", 89 | "high": "More than 4 days of degrade in employee or customer health.", 90 | "critical": "Permenent degrade in employee or customer health", 91 | "low": "No significant threats to health and safety", 92 | "type": "health" 93 | }, 94 | { 95 | "priority": "5", 96 | "medium": "Less than 1 full time employee is required for less than 2 months", 97 | "description": "Productivity", 98 | "high": "Less than 4 full time employees are requred for less than 6 months", 99 | "critical": "More than 4 full time employees are required for more than 6 months", 100 | "low": "Less than 1 full time employee is required for less than 1 month", 101 | "type": "productivity" 102 | } 103 | ], 104 | "container_library": [ 105 | { 106 | "container_description": "", 107 | "container_name": "Network appliances" 108 | }, 109 | { 110 | "container_description": "", 111 | "container_name": "Network appliances - Routers" 112 | }, 113 | { 114 | "container_description": "", 115 | "container_name": "Network appliances - Swithces" 116 | }, 117 | { 118 | "container_description": "", 119 | "container_name": "Network appliances - Firewalls" 120 | }, 121 | { 122 | "container_description": "", 123 | "container_name": "Servers - Web External" 124 | }, 125 | { 126 | "container_description": "", 127 | "container_name": "Servers - Database" 128 | }, 129 | { 130 | "container_description": "", 131 | "container_name": "Servers - Infrastructure" 132 | }, 133 | { 134 | "container_description": "", 135 | "container_name": "Servers - Web Internal" 136 | }, 137 | { 138 | "container_description": "", 139 | "container_name": "Servers - Virtualisation infrastructure" 140 | }, 141 | { 142 | "container_description": "", 143 | "container_name": "Servers" 144 | }, 145 | { 146 | "container_description": "", 147 | "container_name": "Laptops - HR" 148 | }, 149 | { 150 | "container_description": "", 151 | "container_name": "Laptops - Finance" 152 | }, 153 | { 154 | "container_description": "", 155 | "container_name": "Laptops - Management" 156 | }, 157 | { 158 | "container_description": "", 159 | "container_name": "Laptops - Operations" 160 | }, 161 | { 162 | "container_description": "", 163 | "container_name": "Laptops - Research & Development" 164 | }, 165 | { 166 | "container_description": "", 167 | "container_name": "Laptops" 168 | }, 169 | { 170 | "container_description": "", 171 | "container_name": "Managers" 172 | }, 173 | { 174 | "container_description": "", 175 | "container_name": "End-users" 176 | }, 177 | { 178 | "container_description": "", 179 | "container_name": "Employees - Operations" 180 | }, 181 | { 182 | "container_description": "", 183 | "container_name": "Employees - Research & Development" 184 | }, 185 | { 186 | "container_description": "", 187 | "container_name": "Employees - Human Resources" 188 | }, 189 | { 190 | "container_description": "", 191 | "container_name": "Employees - Finance" 192 | }, 193 | { 194 | "container_description": "", 195 | "container_name": "Employees" 196 | }, 197 | { 198 | "container_description": "", 199 | "container_name": "Administrators - Servers" 200 | }, 201 | { 202 | "container_description": "", 203 | "container_name": "Administrators - Network" 204 | }, 205 | { 206 | "container_description": "", 207 | "container_name": "Administrators" 208 | }, 209 | { 210 | "container_description": "USB keys, flash cards, DVDs or external harddrives", 211 | "container_name": "Removable media" 212 | }, 213 | { 214 | "container_description": "Storage Area Networks and other shared storage", 215 | "container_name": "Shared storage" 216 | }, 217 | { 218 | "container_description": "", 219 | "container_name": "Printouts" 220 | }, 221 | { 222 | "container_description": "", 223 | "container_name": "Offices" 224 | }, 225 | { 226 | "container_description": "", 227 | "container_name": "Datacenters" 228 | }, 229 | { 230 | "container_description": "", 231 | "container_name": "Safes" 232 | }, 233 | { 234 | "container_description": "", 235 | "container_name": "Private homes" 236 | }, 237 | { 238 | "container_description": "", 239 | "container_name": "Cables" 240 | }, 241 | { 242 | "container_description": "", 243 | "container_name": "Employees - Vendor" 244 | }, 245 | { 246 | "container_description": "", 247 | "container_name": "Administrators - Vendor" 248 | } 249 | ], 250 | "rxo_values": [ 251 | "Not selected", 252 | "N/A", 253 | "less than 1 hour", 254 | "4 hours", 255 | "8 hours", 256 | "1 day", 257 | "3 days", 258 | "5 days", 259 | "7 days", 260 | "14 days", 261 | "1 month", 262 | "2 months", 263 | "3 months", 264 | "6 months", 265 | "more than 1 year" 266 | ], 267 | "risktable": [ 268 | { 269 | "asset_id": "", 270 | "threat_id": "", 271 | "deliverable_id": "", 272 | "container_id": "", 273 | "process_id": "", 274 | "control_id": "" 275 | } 276 | ], 277 | "containers": [ 278 | { 279 | "container_id": "", 280 | "container_description": "", 281 | "container_name": "" 282 | } 283 | ] 284 | } 285 | -------------------------------------------------------------------------------- /templates/analyse_process.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 4 |

Risk Analysis

5 | {# FORM TO UPDATE PROCESS DETAILS #} 6 | {% for process in process_table %} {#loop ends at end of template!#} 7 | 8 |
9 |

Process

10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 | 21 | 22 |

23 |
24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | {# FORM TO SELECT ASSET TO UPDATE, ADD OR DELETE #} 32 | {% for asset in asset_table %} {# ends at end of template!#} 33 |
34 |
35 |
36 |
37 |

Critical Information

38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 |
58 | 59 | {% set check_c="" %} 60 | {% set check_i="" %} 61 | {% set check_a="" %} 62 | {% if asset.asset_criticality_c == "True" %} {% set check_c="checked" %} {% endif %} 63 | {% if asset.asset_criticality_i == "True" %} {% set check_i="checked" %} {% endif %} 64 | {% if asset.asset_criticality_a == "True" %} {% set check_a="checked" %} {% endif %} 65 |
66 |
67 | 68 | 69 | 70 |
71 |
72 | 73 |
74 |
75 | 76 | 77 | 78 |
79 |
80 | 81 |
82 |
83 | 84 | 85 | 86 |
87 |
88 | 89 |
90 | Recovery point objective 91 | 97 |
98 | 99 |
100 | Recovery time objective 101 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 |
117 |
118 |
119 | 125 | 126 | 127 | 128 | 129 |
130 |
131 | 132 | {# Threat form #} 133 |
134 | {% for threat in threat_table %} 135 | {% if threat.asset_id == asset.asset_id %} 136 |

Threat: {{ threat.threat_name }}

137 |
138 |
139 | 140 | 141 |
142 | 143 |

Impact analysis

144 |
RoleNameSignatureDate
Risk AnalystName:_____________________________Signature:_____________________________Date: ________________
Owner of {{asset.asset_name}}({{asset.asset_owner}})Name:_____________________________Signature:_____________________________Date: ________________
145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | {% for impact_score in threat.impact_scores %} 153 | {% set check0="" %} 154 | {% set check1="" %} 155 | {% set check2="" %} 156 | {% set check3="" %} 157 | {% if impact_score.score == "0" %}{% set check0="checked"%}{% endif %} 158 | {% if impact_score.score == "1" %}{% set check1="checked"%}{% endif %} 159 | {% if impact_score.score == "2" %}{% set check2="checked"%}{% endif %} 160 | {% if impact_score.score == "3" %}{% set check3="checked"%}{% endif %} 161 | 162 | 169 | 183 | 197 | 211 | 225 | 227 | 228 | {% endfor %} 229 |
Impact areaLowMediumHighCritical
163 | {% for global_impact in global_impact_details %} 164 | {% if global_impact.type == impact_score.type %} 165 | {{global_impact.description}} 166 | {% endif %} 167 | {% endfor %} 168 | 170 | 171 | 172 | 173 | 174 | {% for global_impact in global_impact_details %} 175 | {% if global_impact.type == impact_score.type %} 176 | 177 | {% endif %} 178 | {% endfor %} 179 | 180 | 181 | 182 | 184 |
185 |
186 |
187 | 188 | {% for global_impact in global_impact_details %} 189 | {% if global_impact.type == impact_score.type %} 190 | 191 | {% endif %} 192 | {% endfor %} 193 |
194 |
195 |
196 |
198 |
199 |
200 |
201 | 202 | {% for global_impact in global_impact_details %} 203 | {% if global_impact.type == impact_score.type %} 204 | 205 | {% endif %} 206 | {% endfor %} 207 |
208 |
209 |
210 |
212 |
213 |
214 |
215 | 216 | {% for global_impact in global_impact_details %} 217 | {% if global_impact.type == impact_score.type %} 218 | 219 | {% endif %} 220 | {% endfor %} 221 |
222 |
223 |
224 |
226 |
230 | 231 | 232 |

Probability Analysis

233 | Probability of exposure: 234 | {% set check0="" %} 235 | {% set check1="" %} 236 | {% set check2="" %} 237 | {% set check3="" %} 238 | {% if threat.threat_probability == "0" %}{% set check0="checked"%}{% endif %} 239 | {% if threat.threat_probability == "1" %}{% set check1="checked"%}{% endif %} 240 | {% if threat.threat_probability == "2" %}{% set check2="checked"%}{% endif %} 241 | {% if threat.threat_probability == "3" %}{% set check3="checked"%}{% endif %} 242 | 243 | 244 | 245 | 246 | 247 |
Unlikely (every 10+ years)
Occasionally (every 5-10 years)
Likely (every 1-5 years)
Very likely (at least yearly)
248 | 249 |

Risk Treatment Decision

250 | Select one of the following options: 251 | 258 |
259 | Is risk treatment done?: 260 | 265 |
266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 |

Control selection

274 | 275 | 276 | 277 | 278 | 279 | 280 | {% for container in threat.containers|sort(attribute='container_name') %} 281 | 282 | 283 | 293 | 322 | {% endfor %} 323 | 324 |
ContainerControls
284 | 285 |
286 | {{container.container_name}} 287 | 288 | 289 | 290 | 291 |
292 |
294 | 295 | {% for control in container.container_controls %} 296 |
297 | {{control.control_id}} {{control.control_name}} 298 | 299 | 300 | 301 | 302 |
303 | {% endfor %} 304 | 305 |
306 |
307 | 315 | 316 | 317 | 318 | 319 |
320 |
321 |
325 | 326 |
327 |
328 | 335 | 336 | 337 | 338 |
339 |
340 | 341 | {# Threat loop ends here#} 342 | {% endif %} 343 | {% endfor %} 344 |
345 |
346 | 347 | 348 | 349 | {% endfor %} {# asset loop ends here #} 350 | {% endfor %} {# proccess loop ends here#} 351 | 352 | 367 | 368 | {% endblock %} 369 | 370 | -------------------------------------------------------------------------------- /assessments/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "processes": [ 3 | { 4 | "process_description": "", 5 | "process_id": "process000002", 6 | "process_name": "Finance - Budgeting & Reporting", 7 | "process_business_unit": "" 8 | }, 9 | { 10 | "process_name": "Human Resources - Employment", 11 | "process_id": "process000001", 12 | "process_description": "Human Resources department are handling recruitment, performance measurement, compensation/benefits managemnt, salary adjustments and resignations/dismissals for employees in the organisation.", 13 | "process_business_unit": "" 14 | }, 15 | { 16 | "process_name": "Finance - Procurement", 17 | "process_id": "process000003", 18 | "process_description": "", 19 | "process_business_unit": "" 20 | }, 21 | { 22 | "process_name": "IT - Hosting", 23 | "process_id": "process000004", 24 | "process_description": "", 25 | "process_business_unit": "" 26 | }, 27 | { 28 | "process_description": "", 29 | "process_id": "process000005", 30 | "process_name": "IT - Networking", 31 | "process_business_unit": "" 32 | }, 33 | { 34 | "process_description": "", 35 | "process_id": "process000006", 36 | "process_name": "IT - Software development", 37 | "process_business_unit": "" 38 | }, 39 | { 40 | "process_name": "IT - Collaboration", 41 | "process_id": "process000007", 42 | "process_description": "", 43 | "process_business_unit": "" 44 | } 45 | ], 46 | "threats": [ 47 | { 48 | "threat_action_rationale": "", 49 | "threat_id": "threat000001", 50 | "impact_scores": [ 51 | { 52 | "score": "1", 53 | "type": "reputational" 54 | }, 55 | { 56 | "score": "1", 57 | "type": "legal" 58 | }, 59 | { 60 | "score": "1", 61 | "type": "financial" 62 | }, 63 | { 64 | "score": "0", 65 | "type": "health" 66 | }, 67 | { 68 | "score": "3", 69 | "type": "productivity" 70 | } 71 | ], 72 | "threat_description": "All data in the financial database is lost.", 73 | "threat_action": "Modify", 74 | "threat_name": "Availability", 75 | "threat_action_executed": "False", 76 | "threat_probability": "2" 77 | }, 78 | { 79 | "threat_action_rationale": "", 80 | "threat_id": "threat000003", 81 | "impact_scores": [ 82 | { 83 | "score": "0", 84 | "type": "legal" 85 | }, 86 | { 87 | "score": "0", 88 | "type": "financial" 89 | }, 90 | { 91 | "score": "0", 92 | "type": "productivity" 93 | }, 94 | { 95 | "score": "0", 96 | "type": "reputational" 97 | }, 98 | { 99 | "score": "0", 100 | "type": "health" 101 | } 102 | ], 103 | "threat_description": "", 104 | "threat_action": "", 105 | "threat_name": "Availablity", 106 | "threat_action_executed": "", 107 | "threat_probability": "" 108 | } 109 | ], 110 | "assets": [ 111 | { 112 | "asset_id": "asset000001", 113 | "asset_rpo_days": "1 day", 114 | "asset_criticality_i": "True", 115 | "asset_criticality_c": "True", 116 | "asset_description": "Financial database containing record of all transactions is stored the internal database hotel", 117 | "asset_criticality_a": "True", 118 | "asset_owner": "CFO", 119 | "asset_name": "Internal Financial Database", 120 | "process_id": "process000002", 121 | "asset_rto_days": "7 days" 122 | }, 123 | { 124 | "asset_id": "asset000002", 125 | "asset_rpo_days": "Not selected", 126 | "asset_criticality_i": "False", 127 | "asset_criticality_c": "True", 128 | "asset_description": "", 129 | "asset_criticality_a": "False", 130 | "asset_owner": "", 131 | "asset_name": "", 132 | "process_id": "", 133 | "asset_rto_days": "Not selected" 134 | }, 135 | { 136 | "asset_id": "asset000003", 137 | "asset_name": "", 138 | "asset_criticality_i": "False", 139 | "asset_criticality_c": "False", 140 | "asset_description": "", 141 | "asset_criticality_a": "False", 142 | "asset_owner": "", 143 | "asset_rpo_days": "Not selected", 144 | "process_id": "", 145 | "asset_rto_days": "Not selected" 146 | }, 147 | { 148 | "asset_id": "asset000004", 149 | "asset_rpo_days": "1 day", 150 | "asset_criticality_i": "True", 151 | "asset_criticality_c": "False", 152 | "asset_description": "All contracts are stored in a database.", 153 | "asset_criticality_a": "True", 154 | "asset_owner": "CFO", 155 | "asset_name": "Contracts database", 156 | "process_id": "", 157 | "asset_rto_days": "14 days" 158 | } 159 | ], 160 | "global_impact_details": [ 161 | { 162 | "high": "Irrevokable damage to less important stakholders confidence", 163 | "medium": "Revokable damage to reputation and stakeholders confidence", 164 | "description": "Reputation and stakeholder confidence", 165 | "priority": "1", 166 | "critical": "Irrevokable damage to key stakholders confidence or public reputation", 167 | "low": "Minimal damage to reputation and stakeholder confidence", 168 | "type": "reputational" 169 | }, 170 | { 171 | "high": "Fines, non-frivolous lawsuits or investigations exceed 200.000 euro", 172 | "medium": "Fines, non-frivolous lawsuits or investigations do not exceed 200.000 euro", 173 | "description": "Fines and legal penialties", 174 | "priority": "2", 175 | "critical": "Public investigations of organisational practices is made", 176 | "low": "Fines, non-frivolous lawsuits or investigations do not exceed 50.000 euro", 177 | "type": "legal" 178 | }, 179 | { 180 | "high": "Yearly revenue reduction or one time loss of 200.000-500.000 euros", 181 | "medium": "Yearly revenue reduction or one time loss of 50.000-200.000 euros", 182 | "description": "Financial", 183 | "priority": "3", 184 | "critical": "Yearly revenue reduction or one time loss of more than 500.000 euros", 185 | "low": "Yearly revenue reduction or one time loss of less than 50.000 euros", 186 | "type": "financial" 187 | }, 188 | { 189 | "high": "More than 4 days of degrade in employee or customer health.", 190 | "medium": "Maximum 4 days of degrade in employee or customer health.", 191 | "description": "Health and safety", 192 | "priority": "4", 193 | "critical": "Permenent degrade in employee or customer health", 194 | "low": "No significant threats to health and safety", 195 | "type": "health" 196 | }, 197 | { 198 | "high": "Less than 4 full time employees are requred for less than 6 months", 199 | "medium": "Less than 1 full time employee is required for less than 2 months", 200 | "description": "Productivity", 201 | "priority": "5", 202 | "critical": "More than 4 full time employees are required for more than 6 months", 203 | "low": "Less than 1 full time employee is required for less than 1 month", 204 | "type": "productivity" 205 | } 206 | ], 207 | "container_library": [ 208 | { 209 | "container_description": "", 210 | "container_name": "Network appliances" 211 | }, 212 | { 213 | "container_description": "", 214 | "container_name": "Network appliances - Routers" 215 | }, 216 | { 217 | "container_description": "", 218 | "container_name": "Network appliances - Swithces" 219 | }, 220 | { 221 | "container_description": "", 222 | "container_name": "Network appliances - Firewalls" 223 | }, 224 | { 225 | "container_description": "", 226 | "container_name": "Servers - Web External" 227 | }, 228 | { 229 | "container_description": "", 230 | "container_name": "Servers - Database" 231 | }, 232 | { 233 | "container_description": "", 234 | "container_name": "Servers - Infrastructure" 235 | }, 236 | { 237 | "container_description": "", 238 | "container_name": "Servers - Web Internal" 239 | }, 240 | { 241 | "container_description": "", 242 | "container_name": "Servers - Virtualisation infrastructure" 243 | }, 244 | { 245 | "container_description": "", 246 | "container_name": "Servers" 247 | }, 248 | { 249 | "container_description": "", 250 | "container_name": "Laptops - HR" 251 | }, 252 | { 253 | "container_description": "", 254 | "container_name": "Laptops - Finance" 255 | }, 256 | { 257 | "container_description": "", 258 | "container_name": "Laptops - Management" 259 | }, 260 | { 261 | "container_description": "", 262 | "container_name": "Laptops - Operations" 263 | }, 264 | { 265 | "container_description": "", 266 | "container_name": "Laptops - Research & Development" 267 | }, 268 | { 269 | "container_description": "", 270 | "container_name": "Laptops" 271 | }, 272 | { 273 | "container_description": "", 274 | "container_name": "Managers" 275 | }, 276 | { 277 | "container_description": "", 278 | "container_name": "End-users" 279 | }, 280 | { 281 | "container_description": "", 282 | "container_name": "Employees - Operations" 283 | }, 284 | { 285 | "container_description": "", 286 | "container_name": "Employees - Research & Development" 287 | }, 288 | { 289 | "container_description": "", 290 | "container_name": "Employees - Human Resources" 291 | }, 292 | { 293 | "container_description": "", 294 | "container_name": "Employees - Finance" 295 | }, 296 | { 297 | "container_description": "", 298 | "container_name": "Employees" 299 | }, 300 | { 301 | "container_description": "", 302 | "container_name": "Administrators - Servers" 303 | }, 304 | { 305 | "container_description": "", 306 | "container_name": "Administrators - Network" 307 | }, 308 | { 309 | "container_description": "", 310 | "container_name": "Administrators" 311 | }, 312 | { 313 | "container_description": "USB keys, flash cards, DVDs or external harddrives", 314 | "container_name": "Removable media" 315 | }, 316 | { 317 | "container_description": "Storage Area Networks and other shared storage", 318 | "container_name": "Shared storage" 319 | }, 320 | { 321 | "container_description": "", 322 | "container_name": "Printouts" 323 | }, 324 | { 325 | "container_description": "", 326 | "container_name": "Offices" 327 | }, 328 | { 329 | "container_description": "", 330 | "container_name": "Datacenters" 331 | }, 332 | { 333 | "container_description": "", 334 | "container_name": "Safes" 335 | }, 336 | { 337 | "container_description": "", 338 | "container_name": "Private homes" 339 | }, 340 | { 341 | "container_description": "", 342 | "container_name": "Cables" 343 | }, 344 | { 345 | "container_description": "", 346 | "container_name": "Employees - Vendor" 347 | }, 348 | { 349 | "container_description": "", 350 | "container_name": "Administrators - Vendor" 351 | } 352 | ], 353 | "rxo_values": [ 354 | "Not selected", 355 | "less than 1 hour", 356 | "4 hours", 357 | "8 hours", 358 | "1 day", 359 | "3 days", 360 | "5 days", 361 | "7 days", 362 | "14 days", 363 | "1 month", 364 | "2 months", 365 | "3 months", 366 | "6 months", 367 | "more than 1 year" 368 | ], 369 | "containers": [ 370 | { 371 | "container_id": "container000001", 372 | "container_description": "A database server is software and hardware needed to operate the database", 373 | "container_name": "Server - Database" 374 | }, 375 | { 376 | "action": "Add container", 377 | "threat_id": "threat000001", 378 | "container_description": "", 379 | "container_id": "container000002", 380 | "container_name": "Administrators - Servers" 381 | } 382 | ], 383 | "threat_library": [ 384 | { 385 | "threat_name": "Malicious Code", 386 | "threat_description": "Use of code to perform unauthorised disclosure, adjustment or destruction" 387 | }, 388 | { 389 | "threat_name": "Information Gathering", 390 | "threat_description": "Gathering of information" 391 | }, 392 | { 393 | "threat_name": "Intrusions", 394 | "threat_description": "Unauthorised access to data, systems, physical documents, or facilities" 395 | }, 396 | { 397 | "threat_name": "Availablity", 398 | "description": "Unavailability of systems, people, physical documents or facilities" 399 | }, 400 | { 401 | "threat_name": "Information Content Security", 402 | "threat_description": "Unauthorised adjustment of information content" 403 | }, 404 | { 405 | "threat_name": "Fraud", 406 | "threat_description": "Fraud is deliberate deception to secure unfair or unlawful gain, or to deprive a victim of a legal right." 407 | } 408 | ], 409 | "risktable": [ 410 | { 411 | "asset_id": "asset000001", 412 | "process_id": "process000002" 413 | }, 414 | { 415 | "threat_id": "threat000001", 416 | "control_id": "AC-03", 417 | "container_id": "container000001" 418 | }, 419 | { 420 | "threat_id": "threat000001", 421 | "container_id": "container000002" 422 | }, 423 | { 424 | "asset_id": "asset000001", 425 | "threat_id": "threat000002" 426 | }, 427 | { 428 | "asset_id": "asset000002", 429 | "process_id": "process000002" 430 | }, 431 | { 432 | "asset_id": "asset000001", 433 | "threat_id": "threat000001" 434 | }, 435 | { 436 | "process_id": "process000002" 437 | }, 438 | { 439 | "threat_id": "threat000001", 440 | "control_id": "AC-02", 441 | "container_id": "container000001" 442 | }, 443 | { 444 | "threat_id": "threat000001", 445 | "control_id": "AC-03", 446 | "container_id": "container000002" 447 | }, 448 | { 449 | "process_id": "process000001" 450 | }, 451 | { 452 | "process_id": "process000003" 453 | }, 454 | { 455 | "process_id": "process000004" 456 | }, 457 | { 458 | "process_id": "process000005" 459 | }, 460 | { 461 | "asset_id": "asset000003", 462 | "process_id": "process000005" 463 | }, 464 | { 465 | "process_id": "process000006" 466 | }, 467 | { 468 | "process_id": "process000007" 469 | }, 470 | { 471 | "asset_id": "asset000004", 472 | "process_id": "process000003" 473 | }, 474 | { 475 | "asset_id": "asset000004", 476 | "threat_id": "threat000003" 477 | } 478 | ] 479 | } -------------------------------------------------------------------------------- /assessments/control_library.json: -------------------------------------------------------------------------------- 1 | { 2 | "control_library": [ 3 | { 4 | "source": "NIST", 5 | "control_id": "AC-01", 6 | "control_name": "Access Control Policies and Procedures", 7 | "description": "" 8 | }, 9 | { 10 | "source": "NIST", 11 | "control_id": "AC-02", 12 | "control_name": "Account Management", 13 | "description": "" 14 | }, 15 | { 16 | "source": "NIST", 17 | "control_id": "AC-03", 18 | "control_name": "Access Enforcement", 19 | "description": "" 20 | }, 21 | { 22 | "source": "NIST", 23 | "control_id": "AC-04", 24 | "control_name": "Information Flow Enforcement", 25 | "description": "" 26 | }, 27 | { 28 | "source": "NIST", 29 | "control_id": "AC-05", 30 | "control_name": "Separation Of Duties", 31 | "description": "" 32 | }, 33 | { 34 | "source": "NIST", 35 | "control_id": "AC-06", 36 | "control_name": "Least Privilege", 37 | "description": "" 38 | }, 39 | { 40 | "source": "NIST", 41 | "control_id": "AC-07", 42 | "control_name": "Unsuccessful Login Attempts", 43 | "description": "" 44 | }, 45 | { 46 | "source": "NIST", 47 | "control_id": "AC-08", 48 | "control_name": "System Use Notification", 49 | "description": "" 50 | }, 51 | { 52 | "source": "NIST", 53 | "control_id": "AC-09", 54 | "control_name": "Previous Logon Notification", 55 | "description": "" 56 | }, 57 | { 58 | "source": "NIST", 59 | "control_id": "AC-10", 60 | "control_name": "Concurrent Session Control", 61 | "description": "" 62 | }, 63 | { 64 | "source": "NIST", 65 | "control_id": "AC-11", 66 | "control_name": "Session Lock", 67 | "description": "" 68 | }, 69 | { 70 | "source": "NIST", 71 | "control_id": "AC-12", 72 | "control_name": "Session Termination", 73 | "description": "" 74 | }, 75 | { 76 | "source": "NIST", 77 | "control_id": "AC-13", 78 | "control_name": "Supervision And Review -- Access Control", 79 | "description": "" 80 | }, 81 | { 82 | "source": "NIST", 83 | "control_id": "AC-14", 84 | "control_name": "Permitted Actions Without Identification Or Authentication", 85 | "description": "" 86 | }, 87 | { 88 | "source": "NIST", 89 | "control_id": "AC-15", 90 | "control_name": "Automated Marking", 91 | "description": "" 92 | }, 93 | { 94 | "source": "NIST", 95 | "control_id": "AC-16", 96 | "control_name": "Automated Labeling", 97 | "description": "" 98 | }, 99 | { 100 | "source": "NIST", 101 | "control_id": "AC-17", 102 | "control_name": "Remote Access", 103 | "description": "" 104 | }, 105 | { 106 | "source": "NIST", 107 | "control_id": "AC-18", 108 | "control_name": "Wireless Access Restrictions", 109 | "description": "" 110 | }, 111 | { 112 | "source": "NIST", 113 | "control_id": "AC-19", 114 | "control_name": "Access Control For Portable And Mobile Devices", 115 | "description": "" 116 | }, 117 | { 118 | "source": "NIST", 119 | "control_id": "AC-20", 120 | "control_name": "Use Of External Information Systems", 121 | "description": "" 122 | }, 123 | { 124 | "source": "NIST", 125 | "control_id": "AT-01", 126 | "control_name": "Security Awareness And Training Policy And Procedures", 127 | "description": "" 128 | }, 129 | { 130 | "source": "NIST", 131 | "control_id": "AT-02", 132 | "control_name": "Security Awareness", 133 | "description": "" 134 | }, 135 | { 136 | "source": "NIST", 137 | "control_id": "AT-03", 138 | "control_name": "Security Training", 139 | "description": "" 140 | }, 141 | { 142 | "source": "NIST", 143 | "control_id": "AT-04", 144 | "control_name": "Security Training Records", 145 | "description": "" 146 | }, 147 | { 148 | "source": "NIST", 149 | "control_id": "AT-05", 150 | "control_name": "Contacts With Security Groups And Associations", 151 | "description": "" 152 | }, 153 | { 154 | "source": "NIST", 155 | "control_id": "AU-01", 156 | "control_name": "Audit And Accountability Policy And Procedures", 157 | "description": "" 158 | }, 159 | { 160 | "source": "NIST", 161 | "control_id": "AU-02", 162 | "control_name": "Auditable Events", 163 | "description": "" 164 | }, 165 | { 166 | "source": "NIST", 167 | "control_id": "AU-03", 168 | "control_name": "Content Of Audit Records", 169 | "description": "" 170 | }, 171 | { 172 | "source": "NIST", 173 | "control_id": "AU-04", 174 | "control_name": "Audit Storage Capacity", 175 | "description": "" 176 | }, 177 | { 178 | "source": "NIST", 179 | "control_id": "AU-05", 180 | "control_name": "Response To Audit Processing Failures", 181 | "description": "" 182 | }, 183 | { 184 | "source": "NIST", 185 | "control_id": "AU-06", 186 | "control_name": "Audit Monitoring, Analysis, And Reporting", 187 | "description": "" 188 | }, 189 | { 190 | "source": "NIST", 191 | "control_id": "AU-07", 192 | "control_name": "Audit Reduction And Report Generation", 193 | "description": "" 194 | }, 195 | { 196 | "source": "NIST", 197 | "control_id": "AU-08", 198 | "control_name": "Time Stamps", 199 | "description": "" 200 | }, 201 | { 202 | "source": "NIST", 203 | "control_id": "AU-09", 204 | "control_name": "Protection Of Audit Information", 205 | "description": "" 206 | }, 207 | { 208 | "source": "NIST", 209 | "control_id": "AU-10", 210 | "control_name": "Non-Repudiation", 211 | "description": "" 212 | }, 213 | { 214 | "source": "NIST", 215 | "control_id": "AU-11", 216 | "control_name": "Audit Record Retention", 217 | "description": "" 218 | }, 219 | { 220 | "source": "NIST", 221 | "control_id": "CA-01", 222 | "control_name": "Certification, Accreditation, And Security Assessment Policies And Procedures", 223 | "description": "" 224 | }, 225 | { 226 | "source": "NIST", 227 | "control_id": "CA-02", 228 | "control_name": "Security Assessments", 229 | "description": "" 230 | }, 231 | { 232 | "source": "NIST", 233 | "control_id": "CA-03", 234 | "control_name": "Information System Connections", 235 | "description": "" 236 | }, 237 | { 238 | "source": "NIST", 239 | "control_id": "CA-04", 240 | "control_name": "Security Certification", 241 | "description": "" 242 | }, 243 | { 244 | "source": "NIST", 245 | "control_id": "CA-05", 246 | "control_name": "Plan Of Action And Milestones", 247 | "description": "" 248 | }, 249 | { 250 | "source": "NIST", 251 | "control_id": "CA-06", 252 | "control_name": "Security Accreditation", 253 | "description": "" 254 | }, 255 | { 256 | "source": "NIST", 257 | "control_id": "CA-07", 258 | "control_name": "Continuous Monitoring", 259 | "description": "" 260 | }, 261 | { 262 | "source": "NIST", 263 | "control_id": "CM-01", 264 | "control_name": "Configuration Management Policy And Procedures", 265 | "description": "" 266 | }, 267 | { 268 | "source": "NIST", 269 | "control_id": "CM-02", 270 | "control_name": "Baseline Configuration", 271 | "description": "" 272 | }, 273 | { 274 | "source": "NIST", 275 | "control_id": "CM-03", 276 | "control_name": "Configuration Change Control", 277 | "description": "" 278 | }, 279 | { 280 | "source": "NIST", 281 | "control_id": "CM-04", 282 | "control_name": "Monitoring Configuration Changes", 283 | "description": "" 284 | }, 285 | { 286 | "source": "NIST", 287 | "control_id": "CM-05", 288 | "control_name": "Access Restrictions For Change", 289 | "description": "" 290 | }, 291 | { 292 | "source": "NIST", 293 | "control_id": "CM-06", 294 | "control_name": "Configuration Settings", 295 | "description": "" 296 | }, 297 | { 298 | "source": "NIST", 299 | "control_id": "CM-07", 300 | "control_name": "Least Functionality", 301 | "description": "" 302 | }, 303 | { 304 | "source": "NIST", 305 | "control_id": "CM-08", 306 | "control_name": "Information System Component Inventory", 307 | "description": "" 308 | }, 309 | { 310 | "source": "NIST", 311 | "control_id": "CP-01", 312 | "control_name": "Contingency Planning Policy And Procedures", 313 | "description": "" 314 | }, 315 | { 316 | "source": "NIST", 317 | "control_id": "CP-02", 318 | "control_name": "Contingency Plan", 319 | "description": "" 320 | }, 321 | { 322 | "source": "NIST", 323 | "control_id": "CP-03", 324 | "control_name": "Contingency Training", 325 | "description": "" 326 | }, 327 | { 328 | "source": "NIST", 329 | "control_id": "CP-04", 330 | "control_name": "Contingency Plan Testing And Exercises", 331 | "description": "" 332 | }, 333 | { 334 | "source": "NIST", 335 | "control_id": "CP-05", 336 | "control_name": "Contingency Plan Update", 337 | "description": "" 338 | }, 339 | { 340 | "source": "NIST", 341 | "control_id": "CP-06", 342 | "control_name": "Alternate Storage Site", 343 | "description": "" 344 | }, 345 | { 346 | "source": "NIST", 347 | "control_id": "CP-07", 348 | "control_name": "Alternate Processing Site", 349 | "description": "" 350 | }, 351 | { 352 | "source": "NIST", 353 | "control_id": "CP-08", 354 | "control_name": "Telecommunications Services", 355 | "description": "" 356 | }, 357 | { 358 | "source": "NIST", 359 | "control_id": "CP-09", 360 | "control_name": "Information System Backup", 361 | "description": "" 362 | }, 363 | { 364 | "source": "NIST", 365 | "control_id": "CP-10", 366 | "control_name": "Information System Recovery And Reconstitution", 367 | "description": "" 368 | }, 369 | { 370 | "source": "NIST", 371 | "control_id": "IA-01", 372 | "control_name": "Identification And Authentication Policy And Procedures", 373 | "description": "" 374 | }, 375 | { 376 | "source": "NIST", 377 | "control_id": "IA-02", 378 | "control_name": "User Identification And Authentication", 379 | "description": "" 380 | }, 381 | { 382 | "source": "NIST", 383 | "control_id": "IA-03", 384 | "control_name": "Device Identification And Authentication", 385 | "description": "" 386 | }, 387 | { 388 | "source": "NIST", 389 | "control_id": "IA-04", 390 | "control_name": "Identifier Management", 391 | "description": "" 392 | }, 393 | { 394 | "source": "NIST", 395 | "control_id": "IA-05", 396 | "control_name": "Authenticator Management", 397 | "description": "" 398 | }, 399 | { 400 | "source": "NIST", 401 | "control_id": "IA-06", 402 | "control_name": "Authenticator Feedback", 403 | "description": "" 404 | }, 405 | { 406 | "source": "NIST", 407 | "control_id": "IA-07", 408 | "control_name": "Cryptographic Module Authentication", 409 | "description": "" 410 | }, 411 | { 412 | "source": "NIST", 413 | "control_id": "IR-01", 414 | "control_name": "Incident Response Policy And Procedures", 415 | "description": "" 416 | }, 417 | { 418 | "source": "NIST", 419 | "control_id": "IR-02", 420 | "control_name": "Incident Response Training", 421 | "description": "" 422 | }, 423 | { 424 | "source": "NIST", 425 | "control_id": "IR-03", 426 | "control_name": "Incident Response Testing And Exercises", 427 | "description": "" 428 | }, 429 | { 430 | "source": "NIST", 431 | "control_id": "IR-04", 432 | "control_name": "Incident Handling", 433 | "description": "" 434 | }, 435 | { 436 | "source": "NIST", 437 | "control_id": "IR-05", 438 | "control_name": "Incident Monitoring", 439 | "description": "" 440 | }, 441 | { 442 | "source": "NIST", 443 | "control_id": "IR-06", 444 | "control_name": "Incident Reporting", 445 | "description": "" 446 | }, 447 | { 448 | "source": "NIST", 449 | "control_id": "IR-07", 450 | "control_name": "Incident Response Assistance", 451 | "description": "" 452 | }, 453 | { 454 | "source": "NIST", 455 | "control_id": "MA-01", 456 | "control_name": "System Maintenance Policy And Procedures", 457 | "description": "" 458 | }, 459 | { 460 | "source": "NIST", 461 | "control_id": "MA-02", 462 | "control_name": "Controlled Maintenance", 463 | "description": "" 464 | }, 465 | { 466 | "source": "NIST", 467 | "control_id": "MA-03", 468 | "control_name": "Maintenance Tools", 469 | "description": "" 470 | }, 471 | { 472 | "source": "NIST", 473 | "control_id": "MA-04", 474 | "control_name": "Remote Maintenance", 475 | "description": "" 476 | }, 477 | { 478 | "source": "NIST", 479 | "control_id": "MA-05", 480 | "control_name": "Maintenance Personnel", 481 | "description": "" 482 | }, 483 | { 484 | "source": "NIST", 485 | "control_id": "MA-06", 486 | "control_name": "Timely Maintenance", 487 | "description": "" 488 | }, 489 | { 490 | "source": "NIST", 491 | "control_id": "MP-01", 492 | "control_name": "Media Protection Policy And Procedures", 493 | "description": "" 494 | }, 495 | { 496 | "source": "NIST", 497 | "control_id": "MP-02", 498 | "control_name": "Media Access", 499 | "description": "" 500 | }, 501 | { 502 | "source": "NIST", 503 | "control_id": "MP-03", 504 | "control_name": "Media Labeling", 505 | "description": "" 506 | }, 507 | { 508 | "source": "NIST", 509 | "control_id": "MP-04", 510 | "control_name": "Media Storage", 511 | "description": "" 512 | }, 513 | { 514 | "source": "NIST", 515 | "control_id": "MP-05", 516 | "control_name": "Media Transport", 517 | "description": "" 518 | }, 519 | { 520 | "source": "NIST", 521 | "control_id": "MP-06", 522 | "control_name": "Media Sanitization And Disposal", 523 | "description": "" 524 | }, 525 | { 526 | "source": "NIST", 527 | "control_id": "PE-01", 528 | "control_name": "Physical And Environmental Protection Policy And Procedures", 529 | "description": "" 530 | }, 531 | { 532 | "source": "NIST", 533 | "control_id": "PE-02", 534 | "control_name": "Physical Access Authorizations", 535 | "description": "" 536 | }, 537 | { 538 | "source": "NIST", 539 | "control_id": "PE-03", 540 | "control_name": "Physical Access Control", 541 | "description": "" 542 | }, 543 | { 544 | "source": "NIST", 545 | "control_id": "PE-04", 546 | "control_name": "Access Control For Transmission Medium", 547 | "description": "" 548 | }, 549 | { 550 | "source": "NIST", 551 | "control_id": "PE-05", 552 | "control_name": "Access Control For Display Medium", 553 | "description": "" 554 | }, 555 | { 556 | "source": "NIST", 557 | "control_id": "PE-06", 558 | "control_name": "Monitoring Physical Access", 559 | "description": "" 560 | }, 561 | { 562 | "source": "NIST", 563 | "control_id": "PE-07", 564 | "control_name": "Visitor Control", 565 | "description": "" 566 | }, 567 | { 568 | "source": "NIST", 569 | "control_id": "PE-08", 570 | "control_name": "Access Records", 571 | "description": "" 572 | }, 573 | { 574 | "source": "NIST", 575 | "control_id": "PE-09", 576 | "control_name": "Power Equipment And Power Cabling", 577 | "description": "" 578 | }, 579 | { 580 | "source": "NIST", 581 | "control_id": "PE-10", 582 | "control_name": "Emergency Shutoff", 583 | "description": "" 584 | }, 585 | { 586 | "source": "NIST", 587 | "control_id": "PE-11", 588 | "control_name": "Emergency Power", 589 | "description": "" 590 | }, 591 | { 592 | "source": "NIST", 593 | "control_id": "PE-12", 594 | "control_name": "Emergency Lighting", 595 | "description": "" 596 | }, 597 | { 598 | "source": "NIST", 599 | "control_id": "PE-13", 600 | "control_name": "Fire Protection", 601 | "description": "" 602 | }, 603 | { 604 | "source": "NIST", 605 | "control_id": "PE-14", 606 | "control_name": "Temperature And Humidity Controls", 607 | "description": "" 608 | }, 609 | { 610 | "source": "NIST", 611 | "control_id": "PE-15", 612 | "control_name": "Water Damage Protection", 613 | "description": "" 614 | }, 615 | { 616 | "source": "NIST", 617 | "control_id": "PE-16", 618 | "control_name": "Delivery And Removal", 619 | "description": "" 620 | }, 621 | { 622 | "source": "NIST", 623 | "control_id": "PE-17", 624 | "control_name": "Alternate Work Site", 625 | "description": "" 626 | }, 627 | { 628 | "source": "NIST", 629 | "control_id": "PE-18", 630 | "control_name": "Location Of Information System Components", 631 | "description": "" 632 | }, 633 | { 634 | "source": "NIST", 635 | "control_id": "PE-19", 636 | "control_name": "Information Leakage", 637 | "description": "" 638 | }, 639 | { 640 | "source": "NIST", 641 | "control_id": "PL-01", 642 | "control_name": "Security Planning Policy And Procedures", 643 | "description": "" 644 | }, 645 | { 646 | "source": "NIST", 647 | "control_id": "PL-02", 648 | "control_name": "System Security Plan", 649 | "description": "" 650 | }, 651 | { 652 | "source": "NIST", 653 | "control_id": "PL-03", 654 | "control_name": "System Security Plan Update", 655 | "description": "" 656 | }, 657 | { 658 | "source": "NIST", 659 | "control_id": "PL-04", 660 | "control_name": "Rules Of Behavior", 661 | "description": "" 662 | }, 663 | { 664 | "source": "NIST", 665 | "control_id": "PL-05", 666 | "control_name": "Privacy Impact Assessment", 667 | "description": "" 668 | }, 669 | { 670 | "source": "NIST", 671 | "control_id": "PL-06", 672 | "control_name": "Security-Related Activity Planning", 673 | "description": "" 674 | }, 675 | { 676 | "source": "NIST", 677 | "control_id": "PS-01", 678 | "control_name": "Personnel Security Policy And Procedures", 679 | "description": "" 680 | }, 681 | { 682 | "source": "NIST", 683 | "control_id": "PS-02", 684 | "control_name": "Position Categorization", 685 | "description": "" 686 | }, 687 | { 688 | "source": "NIST", 689 | "control_id": "PS-03", 690 | "control_name": "Personnel Screening", 691 | "description": "" 692 | }, 693 | { 694 | "source": "NIST", 695 | "control_id": "PS-04", 696 | "control_name": "Personnel Termination", 697 | "description": "" 698 | }, 699 | { 700 | "source": "NIST", 701 | "control_id": "PS-05", 702 | "control_name": "Personnel Transfer", 703 | "description": "" 704 | }, 705 | { 706 | "source": "NIST", 707 | "control_id": "PS-06", 708 | "control_name": "Access Agreements", 709 | "description": "" 710 | }, 711 | { 712 | "source": "NIST", 713 | "control_id": "PS-07", 714 | "control_name": "Third-Party Personnel Security", 715 | "description": "" 716 | }, 717 | { 718 | "source": "NIST", 719 | "control_id": "PS-08", 720 | "control_name": "Personnel Sanctions", 721 | "description": "" 722 | }, 723 | { 724 | "source": "NIST", 725 | "control_id": "RA-01", 726 | "control_name": "Risk Assessment Policy And Procedures", 727 | "description": "" 728 | }, 729 | { 730 | "source": "NIST", 731 | "control_id": "RA-02", 732 | "control_name": "Security Categorization", 733 | "description": "" 734 | }, 735 | { 736 | "source": "NIST", 737 | "control_id": "RA-03", 738 | "control_name": "Risk Assessment", 739 | "description": "" 740 | }, 741 | { 742 | "source": "NIST", 743 | "control_id": "RA-04", 744 | "control_name": "Risk Assessment Update", 745 | "description": "" 746 | }, 747 | { 748 | "source": "NIST", 749 | "control_id": "RA-05", 750 | "control_name": "Vulnerability Scanning", 751 | "description": "" 752 | }, 753 | { 754 | "source": "NIST", 755 | "control_id": "SA-01", 756 | "control_name": "System And Services Acquisition Policy And Procedures", 757 | "description": "" 758 | }, 759 | { 760 | "source": "NIST", 761 | "control_id": "SA-02", 762 | "control_name": "Allocation Of Resources", 763 | "description": "" 764 | }, 765 | { 766 | "source": "NIST", 767 | "control_id": "SA-03", 768 | "control_name": "Life Cycle Support", 769 | "description": "" 770 | }, 771 | { 772 | "source": "NIST", 773 | "control_id": "SA-04", 774 | "control_name": "Acquisitions", 775 | "description": "" 776 | }, 777 | { 778 | "source": "NIST", 779 | "control_id": "SA-05", 780 | "control_name": "Information System Documentation", 781 | "description": "" 782 | }, 783 | { 784 | "source": "NIST", 785 | "control_id": "SA-06", 786 | "control_name": "Software Usage Restrictions", 787 | "description": "" 788 | }, 789 | { 790 | "source": "NIST", 791 | "control_id": "SA-07", 792 | "control_name": "User Installed Software", 793 | "description": "" 794 | }, 795 | { 796 | "source": "NIST", 797 | "control_id": "SA-08", 798 | "control_name": "Security Engineering Principles", 799 | "description": "" 800 | }, 801 | { 802 | "source": "NIST", 803 | "control_id": "SA-09", 804 | "control_name": "External Information System Services", 805 | "description": "" 806 | }, 807 | { 808 | "source": "NIST", 809 | "control_id": "SA-10", 810 | "control_name": "Developer Configuration Management", 811 | "description": "" 812 | }, 813 | { 814 | "source": "NIST", 815 | "control_id": "SA-11", 816 | "control_name": "Developer Security Testing", 817 | "description": "" 818 | }, 819 | { 820 | "source": "NIST", 821 | "control_id": "SC-01", 822 | "control_name": "System And Communications Protection Policy And Procedures", 823 | "description": "" 824 | }, 825 | { 826 | "source": "NIST", 827 | "control_id": "SC-02", 828 | "control_name": "Application Partitioning", 829 | "description": "" 830 | }, 831 | { 832 | "source": "NIST", 833 | "control_id": "SC-03", 834 | "control_name": "Security Function Isolation", 835 | "description": "" 836 | }, 837 | { 838 | "source": "NIST", 839 | "control_id": "SC-04", 840 | "control_name": "Information Remnance", 841 | "description": "" 842 | }, 843 | { 844 | "source": "NIST", 845 | "control_id": "SC-05", 846 | "control_name": "Denial Of Service Protection", 847 | "description": "" 848 | }, 849 | { 850 | "source": "NIST", 851 | "control_id": "SC-06", 852 | "control_name": "Resource Priority", 853 | "description": "" 854 | }, 855 | { 856 | "source": "NIST", 857 | "control_id": "SC-07", 858 | "control_name": "Boundary Protection", 859 | "description": "" 860 | }, 861 | { 862 | "source": "NIST", 863 | "control_id": "SC-08", 864 | "control_name": "Transmission Integrity", 865 | "description": "" 866 | }, 867 | { 868 | "source": "NIST", 869 | "control_id": "SC-09", 870 | "control_name": "Transmission Confidentiality", 871 | "description": "" 872 | }, 873 | { 874 | "source": "NIST", 875 | "control_id": "SC-10", 876 | "control_name": "Network Disconnect", 877 | "description": "" 878 | }, 879 | { 880 | "source": "NIST", 881 | "control_id": "SC-11", 882 | "control_name": "Trusted Path", 883 | "description": "" 884 | }, 885 | { 886 | "source": "NIST", 887 | "control_id": "SC-12", 888 | "control_name": "Cryptographic Key Establishment And Management", 889 | "description": "" 890 | }, 891 | { 892 | "source": "NIST", 893 | "control_id": "SC-13", 894 | "control_name": "Use Of Cryptography", 895 | "description": "" 896 | }, 897 | { 898 | "source": "NIST", 899 | "control_id": "SC-14", 900 | "control_name": "Public Access Protections", 901 | "description": "" 902 | }, 903 | { 904 | "source": "NIST", 905 | "control_id": "SC-15", 906 | "control_name": "Collaborative Computing", 907 | "description": "" 908 | }, 909 | { 910 | "source": "NIST", 911 | "control_id": "SC-16", 912 | "control_name": "Transmission Of Security Parameters", 913 | "description": "" 914 | }, 915 | { 916 | "source": "NIST", 917 | "control_id": "SC-17", 918 | "control_name": "Public Key Infrastructure Certificates", 919 | "description": "" 920 | }, 921 | { 922 | "source": "NIST", 923 | "control_id": "SC-18", 924 | "control_name": "Mobile Code", 925 | "description": "" 926 | }, 927 | { 928 | "source": "NIST", 929 | "control_id": "SC-19", 930 | "control_name": "Voice Over Internet Protocol", 931 | "description": "" 932 | }, 933 | { 934 | "source": "NIST", 935 | "control_id": "SC-20", 936 | "control_name": "Secure Name / Address Resolution Service (Authoritative Source)", 937 | "description": "" 938 | }, 939 | { 940 | "source": "NIST", 941 | "control_id": "SC-21", 942 | "control_name": "Secure Name / Address Resolution Service (Recursive Or Caching Resolver)", 943 | "description": "" 944 | }, 945 | { 946 | "source": "NIST", 947 | "control_id": "SC-22", 948 | "control_name": "Architecture And Provisioning For Name / Address Resolution Service", 949 | "description": "" 950 | }, 951 | { 952 | "source": "NIST", 953 | "control_id": "SC-23", 954 | "control_name": "Session Authenticity", 955 | "description": "" 956 | }, 957 | { 958 | "source": "NIST", 959 | "control_id": "SI-01", 960 | "control_name": "System And Information Integrity Policy And Procedures", 961 | "description": "" 962 | }, 963 | { 964 | "source": "NIST", 965 | "control_id": "SI-02", 966 | "control_name": "Flaw Remediation", 967 | "description": "" 968 | }, 969 | { 970 | "source": "NIST", 971 | "control_id": "SI-03", 972 | "control_name": "Malicious Code Protection", 973 | "description": "" 974 | }, 975 | { 976 | "source": "NIST", 977 | "control_id": "SI-04", 978 | "control_name": "Information System Monitoring Tools And Techniques", 979 | "description": "" 980 | }, 981 | { 982 | "source": "NIST", 983 | "control_id": "SI-05", 984 | "control_name": "Security Alerts And Advisories", 985 | "description": "" 986 | }, 987 | { 988 | "source": "NIST", 989 | "control_id": "SI-06", 990 | "control_name": "Security Functionality Verification", 991 | "description": "" 992 | }, 993 | { 994 | "source": "NIST", 995 | "control_id": "SI-07", 996 | "control_name": "Software And Information Integrity", 997 | "description": "" 998 | }, 999 | { 1000 | "source": "NIST", 1001 | "control_id": "SI-08", 1002 | "control_name": "Spam Protection", 1003 | "description": "" 1004 | }, 1005 | { 1006 | "source": "NIST", 1007 | "control_id": "SI-09", 1008 | "control_name": "Information Input Restrictions", 1009 | "description": "" 1010 | }, 1011 | { 1012 | "source": "NIST", 1013 | "control_id": "SI-10", 1014 | "control_name": "Information Accuracy, Completeness, Validity, And Authenticity", 1015 | "description": "" 1016 | }, 1017 | { 1018 | "source": "NIST", 1019 | "control_id": "SI-11", 1020 | "control_name": "Error Handling", 1021 | "description": "" 1022 | }, 1023 | { 1024 | "source": "NIST", 1025 | "control_id": "SI-12", 1026 | "control_name": "Information Output Handling And Retention", 1027 | "description": "" 1028 | } 1029 | ] 1030 | } 1031 | -------------------------------------------------------------------------------- /openisms.py: -------------------------------------------------------------------------------- 1 | #sr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ######################### 5 | # External dependencies # 6 | ######################### 7 | from flask import Flask, request, render_template, jsonify, redirect, url_for 8 | import json 9 | import codecs 10 | import os 11 | import re 12 | 13 | DATA = "assessments/data.json" 14 | SCHEMA = "assessments/schema.json" 15 | CONTROL_LIBRARY = "assessments/control_library.json" 16 | DELIVERABLES = "assessments/deliverables.json" 17 | app = Flask(__name__) 18 | 19 | ########################### 20 | # Multi purpose functions # 21 | ########################### 22 | def import_jsondata(selected_file): 23 | """ 24 | Returns dictionary loaded from specified json file 25 | Argument: 26 | selected_file: String such as "assessments/data.json" 27 | """ 28 | f = codecs.open(selected_file, mode='r', encoding='utf-8') 29 | data = json.load(f) 30 | f.close() 31 | return data 32 | 33 | def write_file(filename, contents, charset='utf-8'): 34 | """ 35 | Returns nothing, but writes unicode text to specified file 36 | Arguments: 37 | filename: String, such as "assessments/data.json" 38 | contents: String, such as output form json.dumps() 39 | charset: Must be utf-8 to allow special characters 40 | """ 41 | with open(filename, 'w') as f: 42 | f.write(contents.encode(charset)) 43 | 44 | def fix_json_dict(reference_dict, target_dict): 45 | """ 46 | fix_json_dict 47 | """ 48 | assert(type(reference_dict) is dict) 49 | assert(type(target_dict) is dict) 50 | result = {} 51 | result.update(target_dict) 52 | for rkey, rvalue in reference_dict.iteritems(): 53 | tkey_found=False 54 | for tkey, tvalue in target_dict.iteritems(): 55 | if (rkey in tkey): 56 | tkey_found=True 57 | if not tkey_found: 58 | result.update({rkey:rvalue}) 59 | return result 60 | 61 | def get_impact_type_list(data): 62 | """ 63 | get_impact_type_list returns a list of impact types extracted from data.json 'global_impact_scores' list. 64 | Variable: 65 | - data strcuture loaded form data.json 66 | """ 67 | result=[] 68 | global_impact_details=data.get("global_impact_details",None) 69 | for global_impact_detail in global_impact_details: 70 | impact_type = global_impact_detail.get("type",None) 71 | if impact_type: 72 | result.append(impact_type) 73 | assert(type(result) is list) 74 | return result 75 | 76 | def fix_data_structure(): 77 | data = import_jsondata(DATA) 78 | schema = import_jsondata(SCHEMA) 79 | 80 | for index, process in enumerate(data['processes']): 81 | fixed_process = fix_json_dict(schema['processes'][0],process) 82 | data['processes'][index]=fixed_process 83 | for index, asset in enumerate(data['assets']): 84 | fixed_asset = fix_json_dict(schema['assets'][0],asset) 85 | data['assets'][index]=fixed_asset 86 | for index, threat in enumerate(data['threats']): 87 | fixed_threat = fix_json_dict(schema['threats'][0],threat) 88 | impact_details = threat.get("impact_scores",None) 89 | impact_types = [] 90 | for impact_detail in impact_details: 91 | impact_type = impact_detail.get("type",None) 92 | if impact_type: 93 | impact_types.append(impact_type) 94 | global_impact_types = get_impact_type_list(data) 95 | for global_impact_type in global_impact_types: 96 | if not global_impact_type in impact_types: 97 | new_score = {"type":global_impact_type, "score":"0"} 98 | fixed_threat['impact_scores'].append(new_score) 99 | data['threats'][index]=fixed_threat 100 | output = json.dumps(data, indent=4) 101 | write_file(DATA, output, charset='utf-8') 102 | 103 | 104 | ################## 105 | # Risk functions # 106 | ################## 107 | def get_table(aspect_ids): 108 | """ 109 | get_details returns a list of dictionaries where each 110 | list row is a dictionary with details about aspect_ids. 111 | Arguments: 112 | - aspect_ids must be a list with strings. The aspects 113 | must be of the same kind. 114 | """ 115 | #Check and collect input 116 | assert(type(aspect_ids) is list),"Function get_table only accepts lists" 117 | data=import_jsondata(DATA) 118 | aspect_ids = [x for x in aspect_ids if x is not None] 119 | aspect_ids = sorted(set(aspect_ids)) 120 | control_library=import_jsondata(CONTROL_LIBRARY) 121 | if len(aspect_ids)>0: 122 | aspect_id_sample = aspect_ids[0] 123 | else: 124 | return [] 125 | #Prepare output 126 | if "process" in aspect_id_sample: 127 | aspect_type="process" 128 | aspect_data = data["processes"] 129 | elif "asset" in aspect_id_sample: 130 | aspect_type="asset" 131 | aspect_data = data["assets"] 132 | elif "threat" in aspect_id_sample: 133 | aspect_type="threat" 134 | aspect_data = data["threats"] 135 | elif "container" in aspect_id_sample: 136 | aspect_type="container" 137 | aspect_data = data["containers"] 138 | else: 139 | aspect_type="control" 140 | aspect_data = control_library["control_library"] 141 | result=[] 142 | for aspect_id in aspect_ids: 143 | result_row = {} 144 | id_identifier = aspect_type + "_id" 145 | for item in aspect_data: 146 | row_id = item.get(id_identifier, None) 147 | if (row_id and aspect_id): 148 | if (row_id==aspect_id): 149 | result.append(item) 150 | #Output validation 151 | assert(type(result) is list) 152 | return result 153 | 154 | def get_process_assets(process_ids): 155 | """ 156 | get_process_assets returns a list of asset ids for assets with a given process name 157 | Arguments: 158 | - process_id. A string like "process0000001" 159 | """ 160 | assert(type(process_ids) is list), "get_process_assets got wrong input. Must be list" 161 | process_ids = sorted(set(process_ids)) 162 | data=import_jsondata(DATA) 163 | result = [] 164 | for risk in data["risktable"]: 165 | temp_process_id = risk.get("process_id", None) 166 | temp_asset_id = risk.get("asset_id", None) 167 | if temp_process_id in process_ids: 168 | result.append(temp_asset_id) 169 | result = sorted(set(result)) 170 | assert(type(result) is list), "get_process_assets encountered an error in result variable" 171 | return result 172 | 173 | def get_asset_threats(asset_ids): 174 | """ 175 | Returns a list of threat dictionaries. Each dictionary contains needed information to describe the threat, affected containers and security controls. 176 | Arguments: 177 | - asset_ids: A list of strings in the format "asset" followed by a unique integer number. 178 | """ 179 | assert(type(asset_ids) is list), "get_asset_threats got wrong input. Must be list" 180 | asset_ids = sorted(set(asset_ids)) 181 | data=import_jsondata(DATA) 182 | result = [] 183 | for risk in data["risktable"]: 184 | temp_asset_id = risk.get("asset_id",None) 185 | temp_threat_id = risk.get("threat_id",None) 186 | if temp_asset_id and (temp_asset_id in asset_ids): 187 | result.append(temp_threat_id) 188 | result = sorted(set(result)) 189 | assert(type(result) is list), "get_asset_threats encountered an error in result variable" 190 | return result 191 | 192 | 193 | def get_threat_process(threat_id, data): 194 | assert(type(threat_id) is str) 195 | process_id = None 196 | asset_id = None 197 | for risk in data['risktable']: 198 | var_threat_id = risk.get("threat_id", None) 199 | var_asset_id = risk.get("asset_id",None) 200 | if var_threat_id and var_asset_id: 201 | if var_threat_id == threat_id: 202 | asset_id = var_asset_id 203 | for risk in data['risktable']: 204 | var_process_id = risk.get("process_id",None) 205 | var_asset_id = risk.get("asset_id", None) 206 | if var_process_id and var_asset_id: 207 | if var_asset_id == asset_id: 208 | process_id = var_process_id 209 | return process_id 210 | 211 | def get_control_dict(search_control_id): 212 | """ 213 | Returns a dict with control_id and control_name if searc_control_id is found in control_library.json 214 | Returns an empty dict if nothing is found. 215 | Arguments: 216 | - search_control_id: string with a control_id 217 | """ 218 | assert(type(search_control_id) is str) 219 | control_library=import_jsondata(CONTROL_LIBRARY) 220 | result = {} 221 | for index, control in enumerate(control_library["control_library"]): 222 | control_id = control.get("control_id", None) 223 | if search_control_id in control_id: 224 | control_name = control.get("control_name", None) 225 | result.update({"control_id":control_id,"control_name":control_name}) 226 | assert(type(result) is dict) 227 | return result 228 | 229 | def get_container_dict(search_container_id): 230 | """ 231 | Returns a dict with container_id and container_name from the table containers in data.json 232 | Returns an empty dict if nothgin is found. 233 | Arguments: 234 | - search_container_id: string with container_id 235 | """ 236 | assert(type(search_container_id) is str) 237 | data=import_jsondata(DATA) 238 | result={} 239 | for index, container in enumerate(data["containers"]): 240 | container_id = container.get("container_id", None) 241 | if search_container_id in container_id: 242 | container_name = container.get("container_name", "No name") 243 | result.update({"container_id":container_id, "container_name":container_name}) 244 | assert(type(result) is dict) 245 | return result 246 | 247 | 248 | def get_risk_score(threat_dict): 249 | """ 250 | Returns a risk score as a string with 2 decimals. 251 | Returns "No risk score" string if an error is encountered 252 | The method is based on octave allegro. 253 | Arguments: 254 | - threat_dict: A dict loaded from threats in data.json 255 | """ 256 | data=import_jsondata(DATA) 257 | global_impact_details=data.get("global_impact_details", None) 258 | risk_score = 0.0 259 | impact_scores = threat_dict.get("impact_scores",None) 260 | try: 261 | for global_impact in global_impact_details: 262 | for impact_score in impact_scores: 263 | global_impact_type = global_impact.get("type", None) 264 | impact_score_type = impact_score.get("type", None) 265 | if global_impact_type in impact_score_type: 266 | # note that priority 1 is weighted 5 and 267 | # priority 5 is weigted 1. 268 | # the weight is therefore weight=6-priority 269 | priority = global_impact.get("priority", None) 270 | weight = 6.0-float(priority) 271 | score = float(impact_score.get("score", None)) 272 | risk_score += weight*score 273 | except KeyError,e: 274 | print "get_risk_score error: "+str(e) 275 | 276 | risk_score=risk_score*10.0/45.0 277 | if risk_score>0.0: 278 | result = str('{:04.1f}'.format(risk_score)) 279 | else: 280 | result = "No risk calculated" 281 | assert(type(result) is str) 282 | return result 283 | 284 | 285 | def inject_risk_scores(threat_table): 286 | """ 287 | Returns an a threat table with a new or updated row named "risk score" 288 | Arguments: 289 | - threat_table: A list of threat dicts. 290 | """ 291 | assert(type(threat_table) is list) 292 | for index,threat_dict in enumerate(threat_table): 293 | risk_score=get_risk_score(threat_dict) 294 | threat_table[index].update({"risk_score":risk_score}) 295 | assert(type(threat_table) is list) 296 | return threat_table 297 | 298 | def inject_containers_and_controls(threat_table): 299 | """ 300 | Returns an extended threat_table (list of threat dicts). Each threat dict gets container element injected: 301 | "containers":[ 302 | {"container_id":"", 303 | "container_name":"", 304 | "container_controls":[{"control_id":"","control_name"}] 305 | }] 306 | Arguments: 307 | - threat_table: is a list of threat dicts. 308 | """ 309 | control_library = import_jsondata(CONTROL_LIBRARY) 310 | data=import_jsondata(DATA) 311 | for index,threat_dict in enumerate(threat_table): 312 | containers=[] 313 | containers_reported = [] 314 | asset_id = "" 315 | threat_table_id = threat_dict.get("threat_id",None) 316 | for risk in data["risktable"]: 317 | temp_threat_id = risk.get("threat_id", None) 318 | if temp_threat_id and (temp_threat_id in threat_table_id): 319 | temp_container_id=risk.get("container_id", None) 320 | asset_id = risk.get("asset_id", None) or asset_id 321 | new_data = {} 322 | new_data["container_controls"]=[] 323 | temp_control_ids=[] 324 | if temp_container_id and not (temp_container_id in containers_reported): 325 | container_dict ={} 326 | container_dict=get_container_dict(str(temp_container_id)) 327 | new_data.update(container_dict) 328 | containers_reported.append(str(temp_container_id)) 329 | # loop through all risks with temp_container_id and get container_id 330 | for id_dict in data["risktable"]: 331 | current_container_id = id_dict.get("container_id", None) 332 | if (current_container_id == temp_container_id): 333 | current_control_id =id_dict.get("control_id", None) 334 | if current_control_id: 335 | control_dict = {} 336 | control_dict = get_control_dict(str(current_control_id)) 337 | new_data["container_controls"].append(control_dict) 338 | if new_data.get("container_name",None): 339 | containers.append(new_data) 340 | threat_table[index]["containers"]=containers 341 | threat_table[index]["asset_id"]=asset_id 342 | asset_name="" 343 | asset_owner="" 344 | for asset in data['assets']: 345 | var_asset_id = asset.get("asset_id", None) 346 | if var_asset_id == asset_id: 347 | asset_name=asset.get("asset_name",None) 348 | asset_owner=asset.get("asset_owner",None) 349 | threat_table[index]["asset_name"]=asset_name 350 | threat_table[index]["asset_owner"]=asset_owner 351 | return threat_table 352 | 353 | def apply_to_risktable(risk_dict): 354 | """ 355 | update_risktable updates the risktable element in data.json to contain a specified reference. 356 | Arguments: 357 | - risk_dict contains a dictionary of the format used in risktable. 358 | Example: 359 | X is a unique 6 digit number 360 | { 361 | "asset_id": "assetX", 362 | "container_id": "containerX", 363 | "control_id": "AC-02", 364 | "deliverable_id": "deliverableX", 365 | "process_id": "processX", 366 | "threat_id": "threatX" 367 | } 368 | """ 369 | assert(type(risk_dict) is dict) 370 | assert(len(risk_dict)>0) # Min. 1 keys 371 | assert(len(risk_dict)<4) # Max. 3 keys 372 | data=import_jsondata(DATA) 373 | risk_dict_already_exists=False 374 | for var_dict in data["risktable"]: 375 | if cmp(var_dict, risk_dict)==0: 376 | risk_dict_already_exists=True 377 | if risk_dict_already_exists: 378 | pass 379 | else: 380 | data["risktable"].append(risk_dict) 381 | output = json.dumps(data, indent=4) 382 | write_file(DATA, output, charset='utf-8') 383 | return jsonify(risk_dict) 384 | 385 | def apply_to_aspect(aspect, new_aspect_detail): 386 | """ 387 | update_aspect_details(): 388 | Arguments: 389 | - aspect to update. 390 | - details to update. Must be in a compliant dict format. 391 | """ 392 | assert(type(aspect) is str) 393 | assert(type(new_aspect_detail) is dict) 394 | data=import_jsondata(DATA) 395 | if aspect in "asset": 396 | asset_id_new= new_aspect_detail.get("asset_id", None) 397 | if asset_id_new: 398 | asset_found=False 399 | for index,asset in enumerate(data['assets']): 400 | asset_id_existing=asset.get("asset_id", None) 401 | if asset_id_new in asset_id_existing: 402 | data["assets"][index].update(new_aspect_detail) 403 | asset_found=True 404 | if not asset_found: 405 | data["assets"].append(new_aspect_detail) 406 | else: 407 | return False 408 | elif aspect in "process": 409 | process_id_new = new_aspect_detail.get("process_id", None) 410 | if process_id_new: 411 | process_found=False 412 | for index, process in enumerate(data['processes']): 413 | process_id_existing = process.get("process_id", None) 414 | if process_id_new in process_id_existing: 415 | data["processes"][index].update(new_aspect_detail) 416 | process_found = True 417 | if not process_found: 418 | data["processes"].append(new_aspect_detail) 419 | else: 420 | return False 421 | elif aspect in "threat": 422 | threat_id_new = new_aspect_detail.get("threat_id", None) 423 | if threat_id_new: 424 | threat_found=False 425 | for index, threat in enumerate(data['threats']): 426 | threat_id_existing = threat.get("threat_id", None) 427 | if threat_id_new in threat_id_existing: 428 | threat_found=True 429 | threat_index=index 430 | if threat_found: 431 | new_impact_scores = new_aspect_detail.get("impact_scores",None) 432 | if new_impact_scores: 433 | threat_details=data['threats'][threat_index]['impact_scores'] 434 | for index, old_impact_score in enumerate(threat_details): 435 | for new_impact_score in new_impact_scores: 436 | new_impact_type = new_impact_score.get("type",None) 437 | old_impact_type = old_impact_score.get('type',None) 438 | if new_impact_type in old_impact_type: 439 | data['threats'][threat_index]['impact_scores'][index].update(new_impact_score) 440 | data["threats"][threat_index].update(new_aspect_detail) 441 | if not threat_found: 442 | data["threats"].append(new_aspect_detail) 443 | else: 444 | return False 445 | elif aspect in "container": 446 | container_id_new = new_aspect_detail.get("container_id", None) 447 | if container_id_new: 448 | container_found=False 449 | for index, container in enumerate(data['containers']): 450 | container_id_existing = container.get("container_id", None) 451 | if container_id_new in container_id_existing: 452 | data["containers"][index].update(new_aspect_detail) 453 | container_found = True 454 | if not container_found: 455 | data["containers"].append(new_aspect_detail) 456 | else: 457 | return False 458 | outputdata = json.dumps(data, indent=4) 459 | write_file(DATA, outputdata, charset='utf-8') 460 | return True 461 | 462 | 463 | ########################## 464 | # Web Application Output # 465 | ########################## 466 | @app.route("/", methods=['GET']) 467 | def index(): 468 | """ 469 | Displays Welcome page 470 | """ 471 | return render_template('index.html') 472 | 473 | @app.route("/about", methods=['GET']) 474 | def about(): 475 | """ 476 | Displays About/FAQ page 477 | """ 478 | return render_template('about.html') 479 | 480 | @app.route("/alignment", methods=['GET']) 481 | def alignment(): 482 | data=import_jsondata(DATA) 483 | global_impact_details=data["global_impact_details"] 484 | return render_template("alignment.html", global_impact_details=global_impact_details) 485 | 486 | @app.route("/assessments", methods=['GET']) 487 | def assessments(): 488 | """ 489 | Displays list of processes to analyse or delete 490 | """ 491 | # create process_table 492 | data=import_jsondata(DATA) 493 | process_table=data['processes'] 494 | return render_template('assessments.html',process_table=process_table) 495 | 496 | @app.route("/analyse_process", methods=['GET']) 497 | def analyse_process(): 498 | """ 499 | Displays forms to analyse processes 500 | """ 501 | action=request.args['action'] 502 | process_ids = [] 503 | process_ids.append(request.args['process_id']) 504 | process_table = get_table(process_ids) 505 | if action=="Delete": 506 | process_id = str(process_ids[0]) 507 | if process_id: 508 | depending_ids=delete_cascading_ids(process_id) 509 | for aspect_id in depending_ids: 510 | delete_aspect(str(aspect_id)) 511 | return assessments() 512 | if action=="Analyse": 513 | asset_ids = get_process_assets(process_ids) 514 | asset_table = get_table(asset_ids) 515 | data = import_jsondata(DATA) 516 | rxo_values = data["rxo_values"] 517 | global_impact_details = data["global_impact_details"] 518 | 519 | threat_ids = get_asset_threats(asset_ids) 520 | threat_table = get_table(threat_ids) 521 | threat_table = inject_containers_and_controls(threat_table) 522 | threat_table = inject_risk_scores(threat_table) 523 | threat_library = data.get("threat_library") 524 | control_library = import_jsondata(CONTROL_LIBRARY) 525 | container_library = data.get("container_library", None) 526 | return render_template('analyse_process.html', process_table=process_table, 527 | asset_table=asset_table, 528 | rxo_values=rxo_values, 529 | threat_library = threat_library, 530 | global_impact_details=global_impact_details, 531 | threat_table=threat_table, 532 | control_library=control_library, 533 | container_library=container_library) 534 | if action=="Report": 535 | asset_ids = get_process_assets(process_ids) 536 | asset_table = get_table(asset_ids) 537 | data = import_jsondata(DATA) 538 | rxo_values = data["rxo_values"] 539 | global_impact_details = data["global_impact_details"] 540 | 541 | threat_ids = get_asset_threats(asset_ids) 542 | threat_table = get_table(threat_ids) 543 | threat_table = inject_containers_and_controls(threat_table) 544 | threat_table = inject_risk_scores(threat_table) 545 | threat_library = data.get("threat_library") 546 | control_library = import_jsondata(CONTROL_LIBRARY) 547 | container_library = data.get("container_library", None) 548 | return render_template('report_process.html', process_table=process_table, 549 | asset_table=asset_table, 550 | rxo_values=rxo_values, 551 | threat_library = threat_library, 552 | global_impact_details=global_impact_details, 553 | threat_table=threat_table, 554 | control_library=control_library, 555 | container_library=container_library) 556 | 557 | 558 | 559 | 560 | def get_next_id(aspect_id_type): 561 | """ 562 | get_next_id returns next unique available ID number, depending on aspect_name. 563 | The function will search data dict for any occurences. 564 | If none is found, the first number in the sequence is returned. 565 | Arguments: 566 | - aspect_id_type is one of the keys defined in schema["risktable"]. 567 | """ 568 | schema=import_jsondata(SCHEMA) 569 | risktable_template = schema.get("risktable",None) 570 | aspect_id_types = list(risktable_template[0].keys()) 571 | data = import_jsondata(DATA) 572 | risktable=data.get("risktable", None) 573 | if aspect_id_type is "process_id": 574 | processes=data.get("processes",None) 575 | process_ids=[] 576 | for process in processes: 577 | process_id = process.get("process_id",None) 578 | if process_id: 579 | process_ids.append(process_id) 580 | for risk in risktable: 581 | process_id = risk.get("process_id",None) 582 | if process_id: 583 | process_ids.append(process_id) 584 | if not process_ids: 585 | process_ids.append("process000000") 586 | int_ids = [int(a[7:]) for a in process_ids] 587 | return "process" + str(max(int_ids)+1).zfill(6) 588 | if aspect_id_type is "asset_id": 589 | assets=data.get("assets",None) 590 | asset_ids = [] 591 | for asset in assets: 592 | asset_id = asset.get("asset_id", None) 593 | if asset_id: 594 | asset_ids.append(asset_id) 595 | for risk in risktable: 596 | asset_id = risk.get("asset_id", None) 597 | if asset_id: 598 | asset_ids.append(asset_id) 599 | if not asset_ids: 600 | asset_ids.append("asset000000") 601 | int_ids = [int(a[5:]) for a in asset_ids] 602 | return "asset" + str(max(int_ids)+1).zfill(6) 603 | elif aspect_id_type is "threat_id": 604 | threats=data.get("threats",None) 605 | threat_ids = [] 606 | for threat in threats: 607 | threat_id = threat.get("threat_id", None) 608 | if threat_id: 609 | threat_ids.append(threat_id) 610 | for risk in risktable: 611 | threat_id = risk.get("threat_id", None) 612 | if threat_id: 613 | threat_ids.append(threat_id) 614 | if not threat_ids: 615 | threat_ids.append("threat000000") 616 | int_ids = [int(a[6:]) for a in threat_ids] 617 | return "threat" + str(max(int_ids)+1).zfill(6) 618 | elif aspect_id_type is "container_id": 619 | containers=data.get("containers",None) 620 | container_ids = [] 621 | for container in containers: 622 | container_id = container.get("container_id", None) 623 | if container_id: 624 | container_ids.append(container_id) 625 | for risk in risktable: 626 | container_id = risk.get("container_id", None) 627 | if container_id: 628 | container_ids.append(container_id) 629 | if not container_ids: 630 | container_ids.append("container000000") 631 | int_ids = [int(a[9:]) for a in container_ids] 632 | return "container" + str(max(int_ids)+1).zfill(6) 633 | 634 | @app.route("/add_process", methods=['POST','GET']) 635 | def add_process(): 636 | schema=import_jsondata(SCHEMA) 637 | 638 | process_template = schema['processes'][0] 639 | process_id = get_next_id("process_id") 640 | process_template.update({"process_id":process_id}) 641 | 642 | apply_to_aspect("process", process_template) 643 | risk_ids = {'process_id':process_id} 644 | apply_to_risktable(risk_ids) 645 | return assessments() 646 | 647 | 648 | @app.route("/add_asset", methods=['POST']) 649 | def add_asset(): 650 | schema=import_jsondata(SCHEMA) 651 | asset_template = schema['assets'][0] 652 | asset_id = get_next_id("asset_id") 653 | asset_template.update({"asset_id":asset_id}) 654 | 655 | formdata = {} 656 | f = request.form 657 | for key in f.keys(): 658 | for value in f.getlist(key): 659 | formdata[key] = value.strip() 660 | process_id = formdata.get("process_id",None) 661 | apply_to_aspect("asset", asset_template) 662 | risk_ids = {'process_id':process_id,'asset_id':asset_id} 663 | apply_to_risktable(risk_ids) 664 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 665 | 666 | @app.route("/add_threat", methods=['POST']) 667 | def add_threat(): 668 | schema=import_jsondata(SCHEMA) 669 | threat_template = schema['threats'][0] 670 | threat_id = get_next_id("threat_id") 671 | threat_template.update({"threat_id":threat_id}) 672 | 673 | formdata = {} 674 | f = request.form 675 | for key in f.keys(): 676 | for value in f.getlist(key): 677 | formdata[key] = value.strip() 678 | asset_id = formdata.get("asset_id",None) 679 | process_id = formdata.get("process_id",None) 680 | threat_template['threat_name'] = formdata.get("threat_name","") 681 | 682 | apply_to_aspect("threat", threat_template) 683 | risk_ids = {'asset_id':asset_id,'threat_id':threat_id} 684 | apply_to_risktable(risk_ids) 685 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 686 | 687 | @app.route("/add_container", methods=['POST']) 688 | def add_container(): 689 | formdata = {} 690 | f = request.form 691 | for key in f.keys(): 692 | for value in f.getlist(key): 693 | formdata[key] = value.strip() 694 | threat_id = formdata.get("threat_id",None) 695 | container_id = get_next_id("container_id") 696 | process_id = formdata.get("process_id",None) 697 | formdata.pop("process_id",None) 698 | schema=import_jsondata(SCHEMA) 699 | container_template = schema['containers'][0] 700 | container_template.update(formdata) 701 | container_template.update({'container_id':container_id}) 702 | container_name = container_template.get("container_name",None) 703 | if container_name: 704 | apply_to_aspect("container", container_template) 705 | risk_ids = {'threat_id':threat_id,'container_id':container_id} 706 | apply_to_risktable(risk_ids) 707 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 708 | else: 709 | return "Select a name" 710 | 711 | @app.route("/add_control", methods=['POST']) 712 | def add_control(): 713 | formdata = {} 714 | f = request.form 715 | for key in f.keys(): 716 | for value in f.getlist(key): 717 | formdata[key] = value.strip() 718 | formdata.pop("action",None) 719 | process_id = formdata.get("process_id",None) 720 | formdata.pop("process_id",None) 721 | apply_to_risktable(formdata) 722 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 723 | 724 | @app.route("/update_process", methods=['POST']) 725 | def update_process(): 726 | formdata = {} 727 | f = request.form 728 | new_process_data = {} 729 | for key in f.keys(): 730 | for value in f.getlist(key): 731 | new_process_data[key] = value.strip() 732 | process_id = new_process_data.get("process_id",None) 733 | action = new_process_data.get("action",None) 734 | new_process_data.pop("action", None) 735 | apply_to_aspect("process", new_process_data) 736 | risk_ids = {'process_id':process_id} 737 | apply_to_risktable(risk_ids) 738 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 739 | 740 | @app.route("/update_asset", methods=['POST']) 741 | def update_asset(): 742 | #extract form data 743 | formdata = {} 744 | f = request.form 745 | new_asset_data = {} 746 | for key in f.keys(): 747 | for value in f.getlist(key): 748 | new_asset_data[key] = value.strip() 749 | action = new_asset_data.get("action",None) 750 | process_id = new_asset_data.get("process_id",None) 751 | asset_id = new_asset_data.get("asset_id",None) 752 | if action == "Delete asset": 753 | if asset_id: 754 | depending_ids=[] 755 | depending_ids=delete_cascading_ids(str(asset_id)) 756 | for aspect_id in depending_ids: 757 | delete_aspect(str(aspect_id)) 758 | if action == "Apply asset changes": 759 | #clean data before storage 760 | new_asset_data.pop("process_id",None) 761 | new_asset_data.pop("action",None) 762 | apply_to_aspect("asset", new_asset_data) 763 | #store id comination 764 | risk_ids = {'process_id':process_id,'asset_id':asset_id} 765 | apply_to_risktable(risk_ids) 766 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 767 | 768 | @app.route("/update_threat", methods=['POST']) 769 | def update_threat(): 770 | # Get formdata 771 | formdata = {} 772 | f = request.form 773 | for key in f.keys(): 774 | for value in f.getlist(key): 775 | formdata[key] = value.strip() 776 | action = formdata.get('action',None) 777 | # Update risktable 778 | process_id = formdata.get('process_id',None) 779 | threat_id = formdata.get('threat_id',None) 780 | asset_id = formdata.get("asset_id",None) 781 | if action == "Delete threat": 782 | if threat_id: 783 | depending_ids=[] 784 | depending_ids=delete_cascading_ids(str(threat_id)) 785 | for aspect_id in depending_ids: 786 | delete_aspect(str(aspect_id)) 787 | if action == "Apply threat changes": 788 | risk_ids = {"threat_id":threat_id, "asset_id":asset_id} 789 | apply_to_risktable(risk_ids) 790 | # Clean formdata 791 | formdata.pop("action",None) 792 | formdata.pop("asset_id",None) 793 | # Get list of impact_score_types from data.json 794 | impact_score_types=[] 795 | data=import_jsondata(DATA) 796 | global_impact_details=data.get("global_impact_details",None) 797 | for global_impact_detail in global_impact_details: 798 | impact_score_types.append(global_impact_detail.get("type",None)) 799 | # Create datastructure for impact_scores and update formdata. 800 | impact_scores=[] 801 | for impact_score_type in impact_score_types: 802 | formdata_variable = formdata.get(impact_score_type, None) 803 | if formdata_variable in ["0","1","2","3"]: 804 | impact_score={} 805 | impact_score['score']=str(formdata_variable) 806 | impact_score['type']=impact_score_type 807 | impact_scores.append(impact_score) 808 | formdata.pop(impact_score_type,None) 809 | formdata['impact_scores']=impact_scores 810 | # Store data 811 | apply_to_aspect("threat", formdata) 812 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 813 | 814 | def delete_id_set(id_1, id_2): 815 | """ 816 | delete_id deletes all lines from risktable in data.json, containing both ids. 817 | Arguments: 818 | - id_1: first id, e.g. "container_000001" 819 | - id_2: second id, e.g. "control000001" 820 | """ 821 | assert(type(id_1) is str) 822 | assert(type(id_2) is str) 823 | data=import_jsondata(DATA) 824 | old_risktable = data.get("risktable",None) 825 | new_risktable = [] 826 | for risk in old_risktable: 827 | id_1_found=False 828 | id_2_found=False 829 | for key,value in risk.iteritems(): 830 | if value==id_1: id_1_found=True 831 | if value==id_2: id_2_found=True 832 | if not (id_1_found and id_2_found): 833 | new_risktable.append(risk) 834 | data['risktable']=new_risktable 835 | output = json.dumps(data, indent=4) 836 | write_file(DATA, output, charset='utf-8') 837 | return True 838 | 839 | def delete_cascading_ids(aspect_id): 840 | assert(type(aspect_id) is str) 841 | prefix = aspect_id[0:5] 842 | assert(prefix in ["proce","asset","threa"]) 843 | data=import_jsondata(DATA) 844 | old_risktable = data.get("risktable",None) 845 | id_order = ["process_id","asset_id","threat_id"] 846 | remove_list=[] 847 | remove_list.append(aspect_id) 848 | for risk in old_risktable: 849 | remove_risk = False 850 | for id_type in id_order: 851 | for id_key, id_value in risk.iteritems(): 852 | if id_type == id_key: 853 | if id_value in remove_list: 854 | remove_risk=True 855 | break 856 | if remove_risk: 857 | for id_key, id_value in risk.iteritems(): 858 | if id_type==id_key: 859 | remove_list.append(id_value) 860 | new_risktable = [] 861 | for risk in old_risktable: 862 | keep_risk=True 863 | for id_key, id_value in risk.iteritems(): 864 | if id_value in remove_list: 865 | keep_risk=False 866 | if keep_risk: 867 | new_risktable.append(risk) 868 | data['risktable']=new_risktable 869 | output = json.dumps(data, indent=4) 870 | write_file(DATA, output, charset='utf-8') 871 | return list(set(remove_list)) 872 | 873 | def delete_aspect(aspect_id): 874 | assert(type(aspect_id) is str) 875 | ref = "" 876 | key = "" 877 | if aspect_id[0:7]=="process": 878 | ref="processes" 879 | key="process_id" 880 | elif aspect_id[0:5]=="asset": 881 | ref="assets" 882 | key="asset_id" 883 | elif aspect_id[0:6]=="threat": 884 | ref="threats" 885 | key="threat_id" 886 | if ref: 887 | data=import_jsondata(DATA) 888 | for index,aspect in enumerate(data[ref]): 889 | row_id = aspect.get(key,None) 890 | if row_id == aspect_id: 891 | data[ref].pop(index) 892 | break 893 | output = json.dumps(data, indent=4) 894 | write_file(DATA, output, charset='utf-8') 895 | return True 896 | 897 | @app.route("/delete_control",methods=['POST','GET']) 898 | def delete_control(): 899 | formdata = {} 900 | f = request.form 901 | for key in f.keys(): 902 | for value in f.getlist(key): 903 | formdata[key] = value.strip() 904 | process_id = formdata.get('process_id',None) 905 | control_id = formdata.get("control_id",None) 906 | container_id = formdata.get("container_id",None) 907 | if control_id and container_id: 908 | delete_id_set(str(control_id),str(container_id)) 909 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 910 | 911 | @app.route("/delete_container",methods=['POST','GET']) 912 | def delete_container(): 913 | formdata = {} 914 | f = request.form 915 | for key in f.keys(): 916 | for value in f.getlist(key): 917 | formdata[key] = value.strip() 918 | process_id = formdata.get('process_id',None) 919 | threat_id = formdata.get("threat_id",None) 920 | container_id = formdata.get("container_id",None) 921 | if container_id and threat_id: 922 | delete_id_set(str(threat_id),str(container_id)) 923 | return redirect(url_for('analyse_process',process_id=process_id,action='Analyse')) 924 | 925 | 926 | @app.route("/show_json", methods=['GET']) 927 | def show_json(): 928 | data = import_jsondata(DATA) 929 | return jsonify(data) 930 | 931 | @app.route("/reports", methods=['GET']) 932 | def reports(): 933 | return render_template("reports.html") 934 | 935 | @app.route("/risk_acceptance", methods=['GET']) 936 | def risk_acceptance(): 937 | return render_template("risk_acceptance.html") 938 | 939 | @app.route("/controls_soa", methods=['GET']) 940 | def controls_soa(): 941 | data = import_jsondata(DATA) 942 | control_library=import_jsondata(CONTROL_LIBRARY) 943 | control_table = control_library['control_library'] 944 | for index,control in enumerate(control_table): 945 | control_id = control.get("control_id",None) 946 | control_counter=0 947 | control_containers=[] 948 | if control_id: 949 | #find control_containers+control_counter 950 | for risk in data['risktable']: 951 | risktable_control_id=risk.get("control_id",None) 952 | if control_id==risktable_control_id: 953 | control_counter+=1 954 | container_id = risk.get("container_id",None) 955 | if container_id: 956 | container_dict=get_container_dict(str(container_id)) 957 | container_name=container_dict.get("container_name", "None") 958 | control_containers.append(container_name) 959 | #find control_assets 960 | related_ids = [] 961 | for risk in data['risktable']: 962 | risktable_control_id = risk.get("control_id", None) 963 | risktable_container_id = risk.get("container_id", None) 964 | if control_id == risktable_control_id: 965 | if risktable_control_id and risktable_container_id: 966 | related_ids.append(risktable_container_id) 967 | for risk in data['risktable']: 968 | risktable_container_id = risk.get("container_id", None) 969 | risktable_threat_id = risk.get("threat_id",None) 970 | if risktable_container_id in related_ids: 971 | related_ids.append(risktable_threat_id) 972 | control_asset_ids =[] 973 | for risk in data['risktable']: 974 | risktable_threat_id = risk.get("threat_id",None) 975 | risktable_asset_id = risk.get("asset_id", None) 976 | if risktable_threat_id in related_ids: 977 | control_asset_ids.append(risktable_asset_id) 978 | control_assets=[] 979 | for asset in data['assets']: 980 | asset_id=asset.get("asset_id",None) 981 | if asset_id in control_asset_ids: 982 | asset_name = asset.get("asset_name",None) 983 | control_assets.append(asset_name) 984 | control_table[index]["control_containers"]=set(control_containers) 985 | control_table[index]["control_assets"]=set(control_assets) 986 | control_table[index]["control_count"]=control_counter 987 | 988 | deliverables = import_jsondata(DELIVERABLES) 989 | deliverable_names=[] 990 | for deliverable in deliverables["deliverables"]: 991 | deliverable_control_references = deliverable.get("controls",None) 992 | if deliverable_control_references: 993 | for dcontrol_id in deliverable_control_references: 994 | if dcontrol_id == control_id: 995 | deliverable_name = deliverable.get("name", None) 996 | if deliverable_name: 997 | deliverable_names.append(deliverable_name) 998 | control_table[index]["deliverable_names"]=set(deliverable_names) 999 | return render_template("controls_soa.html",control_table=control_table) 1000 | 1001 | @app.route("/deliverables", methods=['GET']) 1002 | def deliverables(): 1003 | data = import_jsondata(DATA) 1004 | deliverables_import = import_jsondata(DELIVERABLES) 1005 | deliverables_table = deliverables_import['deliverables'] 1006 | # Count the number of times the deliverable was relevant in the SOA 1007 | control_library=import_jsondata(CONTROL_LIBRARY) 1008 | control_table = control_library['control_library'] 1009 | for index,control in enumerate(control_table): 1010 | control_id = control.get("control_id",None) 1011 | control_counter=0 1012 | if control_id: 1013 | for risk in data['risktable']: 1014 | risktable_control_id=risk.get("control_id",None) 1015 | if control_id==risktable_control_id: 1016 | control_counter+=1 1017 | index_to_change = None 1018 | for index2,deliverable in enumerate(deliverables_table): 1019 | deliverable_control_references = deliverable.get("controls",None) 1020 | for dcontrol_id in deliverable_control_references: 1021 | if dcontrol_id == control_id: 1022 | index_to_change = index2 1023 | if index_to_change: 1024 | deliverables_table[index_to_change]["count"]=control_counter 1025 | deliverable_maturity = deliverables_import.get("deliverable_maturity",None) 1026 | return render_template("deliverables.html", deliverables_table=deliverables_table, deliverable_maturity=deliverable_maturity) 1027 | 1028 | @app.route("/update_deliverables", methods=['POST']) 1029 | def update_deliverables(): 1030 | deliverables_import = import_jsondata(DELIVERABLES) 1031 | formdata = {} 1032 | f = request.form 1033 | for key in f.keys(): 1034 | for value in f.getlist(key): 1035 | formdata[key] = value.strip() 1036 | maturity_current = formdata.get('maturity_current',None) 1037 | maturity_planned = formdata.get('maturity_planned',None) 1038 | name = formdata.get('name', None) 1039 | if name: 1040 | delivery_index = None 1041 | for index, deliverable in enumerate(deliverables_import["deliverables"]): 1042 | var_name = deliverable.get("name", None) 1043 | if var_name == name: 1044 | delivery_index = index 1045 | break 1046 | if delivery_index != None: 1047 | deliverables_import["deliverables"][delivery_index].update(formdata) 1048 | output = json.dumps(deliverables_import, indent=4) 1049 | write_file(DELIVERABLES, output, charset='utf-8') 1050 | return deliverables() 1051 | 1052 | @app.route("/risk_report", methods=['POST','GET']) 1053 | def risk_report(): 1054 | data = import_jsondata(DATA) 1055 | threat_ids=[] 1056 | for risk in data['risktable']: 1057 | threat_id = risk.get('threat_id',None) 1058 | if threat_id: 1059 | threat_ids.append(threat_id) 1060 | threat_table = get_table(threat_ids) 1061 | threat_table = inject_containers_and_controls(threat_table) 1062 | threat_table = inject_risk_scores(threat_table) 1063 | for index,threat in enumerate(threat_table): 1064 | process_name = "" 1065 | threat_id = threat.get("threat_id", None) 1066 | process_id = get_threat_process(str(threat_id), data) 1067 | for process in data['processes']: 1068 | var_process_id = process.get("process_id", None) 1069 | if var_process_id: 1070 | if process_id == var_process_id: 1071 | process_name = process.get("process_name", "") 1072 | threat_table[index]['process_name']=process_name 1073 | return render_template("risk_report.html",threat_table=threat_table) 1074 | 1075 | ############# 1076 | # Main code # 1077 | ############# 1078 | if __name__ == '__main__': 1079 | fix_data_structure() 1080 | # Try and get HOSTNAME env variable, defaults to 127.0.0.1 1081 | host = os.getenv('HOSTNAME', '127.0.0.1') 1082 | app.run(host=host) 1083 | # Will debug if DEBUG is set to anything, otherwise false 1084 | debug = not not (os.getenv('DEBUG', False)) 1085 | app.run(host=host,debug=debug) 1086 | -------------------------------------------------------------------------------- /static/jquery.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v2.2.2 | (c) jQuery Foundation | jquery.org/license */ 2 | !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.2",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c; 3 | }catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("