Skip to content

Commit

Permalink
Remove plaintext passwords from HTML. Fixes #921.
Browse files Browse the repository at this point in the history
  • Loading branch information
fniessink committed Jan 13, 2020
1 parent 6380564 commit f3a2e62
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 7 deletions.
21 changes: 21 additions & 0 deletions components/server/src/model/transformations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Model transformations."""

from typing import Iterator


def _sources(report) -> Iterator:
"""Return all sources in the report."""
for subject in report.get("subjects", {}).values():
for metric in subject.get("metrics", {}).values():
yield from metric.get("sources", {}).values()


def hide_credentials(data_model, *reports) -> None:
"""Hide the credentials in the reports."""
data_model_sources = data_model["sources"]
for report in reports:
for source in _sources(report):
for parameter_key, parameter_value in source.get("parameters", {}).items():
if parameter_value and \
data_model_sources[source["type"]]["parameters"][parameter_key]["type"] == "password":
source["parameters"][parameter_key] = "this string replaces credentials"
3 changes: 3 additions & 0 deletions components/server/src/routes/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
from pymongo.database import Database

from database import sessions
from database.datamodels import latest_datamodel
from database.reports import get_data, latest_summarized_reports, insert_new_report, summarize_report
from model.actions import copy_report
from model.transformations import hide_credentials
from initialization.report import import_json_report
from server_utilities.functions import report_date_time, uuid
from server_utilities.type import ReportId
Expand Down Expand Up @@ -86,6 +88,7 @@ def get_tag_report(tag: str, database: Database):
"""Get a report with all metrics that have the specified tag."""
date_time = report_date_time()
reports = latest_summarized_reports(database, date_time)
hide_credentials(latest_datamodel(database), *reports)
subjects = _get_subjects_and_metrics_by_tag(reports, tag)
tag_report = dict(
title=f'Report for tag "{tag}"', subtitle="Note: tag reports are read-only", report_uuid=f"tag-{tag}",
Expand Down
5 changes: 4 additions & 1 deletion components/server/src/routes/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from pymongo.database import Database

from database import sessions
from database.reports import latest_summarized_reports, latest_reports_overview, insert_new_reports_overview
from database.reports import latest_datamodel, latest_summarized_reports, latest_reports_overview, \
insert_new_reports_overview
from model.transformations import hide_credentials
from server_utilities.functions import report_date_time


Expand All @@ -15,6 +17,7 @@ def get_reports(database: Database):
date_time = report_date_time()
overview = latest_reports_overview(database, date_time)
overview["reports"] = latest_summarized_reports(database, date_time)
hide_credentials(latest_datamodel(database), *overview["reports"])
return overview


Expand Down
5 changes: 4 additions & 1 deletion components/server/tests/routes/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ def create_report():
sources={
SOURCE_ID: dict(
type="source_type",
name="Source")})})})
name="Source",
parameters=dict(
url="https://url",
password="password"))})})})
4 changes: 3 additions & 1 deletion components/server/tests/routes/test_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,9 @@ def test_get_metrics(self):
self.assertEqual(
{METRIC_ID: dict(
report_uuid=REPORT_ID, name="Metric", addition="sum", accept_debt=False, type="metric_type", tags=[],
sources=dict(source_uuid=dict(name="Source", type="source_type")))},
sources=dict(
source_uuid=dict(
name="Source", type="source_type", parameters=dict(url="https://url", password="password"))))},
get_metrics(self.database))

def test_delete_metric(self):
Expand Down
2 changes: 1 addition & 1 deletion components/server/tests/routes/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def test_get_tag_report(self, request):
self.maxDiff = None # pylint: disable=invalid-name
request.query = dict(report_date=(date_time := iso_timestamp()))
self.database.datamodels.find_one.return_value = dict(
_id="id", metrics=dict(metric_type=dict(default_scale="count")))
_id="id", sources={}, metrics=dict(metric_type=dict(default_scale="count")))
self.database.reports.find_one.return_value = dict(
_id="id", report_uuid=REPORT_ID, title="Report",
subjects={
Expand Down
6 changes: 4 additions & 2 deletions components/server/tests/routes/test_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ def test_post_reports_attribute_layout(self, request):
self.assertEqual("Jenny changed the layout of the reports overview.", inserted["delta"]["description"])

def test_get_report(self):
"""Test that a report can be retrieved."""
"""Test that a report can be retrieved and credentials are hidden."""
self.database.datamodels.find_one.return_value = dict(
_id="id", metrics=dict(metric_type=dict(default_scale="count")))
_id="id",
sources=dict(source_type=dict(parameters=dict(url=dict(type="url"), password=dict(type="password")))),
metrics=dict(metric_type=dict(default_scale="count")))
self.database.reports_overviews.find_one.return_value = dict(_id="id", title="Reports", subtitle="")
self.database.measurements.find.return_value = [
dict(
Expand Down
3 changes: 2 additions & 1 deletion components/server/tests/routes/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ def setUp(self):
sources=dict(
type=dict(
parameters=dict(
url=dict(type="url"), username=dict(type="string"), password=dict(type="password")))))
url=dict(type="url"), username=dict(type="string"), password=dict(type="password"),
private_token=dict(type="password")))))
self.database.datamodels.find_one.return_value = self.datamodel
self.database.measurements.find.return_value = []
self.url_check_get_response = Mock(status_code=self.STATUS_CODE, reason=self.STATUS_CODE_REASON)
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add report title to subject names in tag reports so it is clear from which report each subject comes. Fixes [#880](https://github.com/ICTU/quality-time/issues/880).
- Tag reports could not be exported to PDF. Fixes [#885](https://github.com/ICTU/quality-time/issues/885).
- Prevent users from entering invalid percentages. Fixes [#888](https://github.com/ICTU/quality-time/issues/888).
- Remove plaintext passwords from HTML. Fixes [#921](https://github.com/ICTU/quality-time/issues/921).

## [1.2.0] - [2019-12-10]

Expand Down

0 comments on commit f3a2e62

Please sign in to comment.