-
Notifications
You must be signed in to change notification settings - Fork 33
Remove report_id from measurement submission #1195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 13 commits
e38bc1a
393d254
c804c84
77a5ecf
dff6de5
69a1628
dc5ee4e
198bb1e
5374c5c
90d52f3
eea7d17
a973560
0582837
2e9739d
1843154
22bc4f4
b383f67
45e46d9
acbf2ba
72c2b81
41d6bff
8d7dba6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,10 +48,12 @@ | |
| PsiphonConfigDep | ||
| ) | ||
| from ...utils import ( | ||
| check_measurement_meta, | ||
| extract_probe_ipaddr, | ||
| generate_report_id, | ||
| geolookup_probe, | ||
| get_cc_asn, | ||
| metadata_from_measurement_content, | ||
| normalize_asn, | ||
| register_geoip_anomaly, | ||
| ) | ||
|
|
@@ -872,9 +874,8 @@ class SubmitMeasurementResponse(BaseModel): | |
| ) | ||
|
|
||
|
|
||
| @router.post("/submit_measurement/{report_id}", tags=["anonymous_credentials"]) | ||
| @router.post("/submit_measurement", tags=["anonymous_credentials"]) | ||
| async def submit_measurement( | ||
| report_id: str, | ||
| request: Request, | ||
| submit_request: SubmitMeasurementRequest, | ||
| response: Response, | ||
|
|
@@ -900,61 +901,29 @@ async def submit_measurement( | |
| - status code 4xx or 5xx: the measurement was not processed nor stored | ||
| """ | ||
| setnocacheresponse(response) | ||
| try: | ||
| rid_timestamp, test_name, cc, asn, format_cid, rand = report_id.split("_") | ||
| except Exception: | ||
| err_msg = f"Incorrect format: unexpected report_id {report_id[:200]}" | ||
| log.info(err_msg) | ||
| raise HTTPException( | ||
| status_code=400, | ||
| detail={"error": "incorrect_format", "message": err_msg}, | ||
| ) | ||
|
|
||
| # TODO validate the timestamp? | ||
| good = len(cc) == 2 and test_name.isalnum() and 1 < len(test_name) < 30 | ||
| if not good: | ||
| err_msg = f"Incorrect format: unexpected report_id {report_id[:200]}" | ||
| log.info(err_msg) | ||
| raise HTTPException( | ||
| status_code=400, | ||
| detail={"error": "incorrect_format", "message": err_msg}, | ||
| ) | ||
| metadata = metadata_from_measurement_content(submit_request.content) | ||
|
|
||
| try: | ||
| asn_i = int(asn) | ||
| except ValueError: | ||
| err_msg = f"Incorrect format: ASN value not parsable {asn}" | ||
| log.info(err_msg) | ||
| raise HTTPException( | ||
| status_code=400, | ||
| detail={"error": "incorrect_format", "message": err_msg}, | ||
| ) | ||
| test_name = metadata.test_name | ||
| cc = metadata.probe_cc | ||
| asn = metadata.probe_asn | ||
|
|
||
| if asn_i == 0: | ||
| log.info("Discarding ASN == 0") | ||
| Metrics.MSMNT_DISCARD_ASN0.inc() | ||
| raise HTTPException(400, detail = {"error" : "asn_0", "message" : "Measurement discarded, ASN == 0"}) | ||
| check_measurement_meta(test_name, cc, asn) | ||
|
|
||
| if cc.upper() == "ZZ": | ||
| log.info("Discarding CC == ZZ") | ||
| Metrics.MSMNT_DISCARD_CC_ZZ.inc() | ||
| raise HTTPException(400, detail = {"error" : "cc_zz", "message" : "Measurement discarded, CC == ZZ"}) | ||
| # generate the new report_id | ||
| rid = generate_report_id(test_name, settings, cc, normalize_asn(asn)) | ||
|
|
||
| # Anonymous credentials verification | ||
| verification_status, submit_error, submit_response = _verify_submit( | ||
| submit_request, manifest, settings | ||
| ) | ||
|
|
||
| annotations = submit_request.content.get("annotations", {}) | ||
| platform = annotations.get("platform") or "" | ||
| software_name = submit_request.content.get("software_name") or "" | ||
| software_version = submit_request.content.get("software_version") or "" | ||
|
|
||
| data = submit_request.model_dump() | ||
|
|
||
| # Add verification-related data. | ||
| # use one-letter code for DB, human readable for clients | ||
| data["is_verified"] = verification_status.code | ||
| data["content"]["report_id"] = rid | ||
| data_buff = io.BytesIO() | ||
| stream = io.TextIOWrapper(data_buff, "utf-8") | ||
| ujson.dump(data, stream) | ||
|
|
@@ -1013,9 +982,9 @@ async def submit_measurement( | |
| cc, | ||
| asn, | ||
| msmt_uid, | ||
| platform, | ||
| software_name, | ||
| software_version, | ||
| metadata.platform, | ||
| metadata.software_name, | ||
| metadata.software_version, | ||
| ) | ||
| except Exception as e: | ||
| log.error(f"Error checking for geoip anomalies: {e}") | ||
|
|
@@ -1031,19 +1000,21 @@ async def submit_measurement( | |
| Metrics.SEND_FASTPATH_CNT.labels(status="fail").inc() | ||
|
|
||
| # wasn't possible to send msmnt to fastpath, try to send it to s3 | ||
| data_buff.seek(0) | ||
| ts_prefix = now.strftime("%Y%m%d%H") | ||
| tn = test_name.replace("_", "") | ||
| s3_key = f"postcans/{ts_prefix}/{ts_prefix}_{cc}_{tn}/{msmt_uid}.post" | ||
| try: | ||
| await run_in_threadpool( | ||
| request.app.state.s3_client.upload_fileobj, | ||
| data_buff, | ||
| io.BytesIO(data_bin), | ||
| Bucket=settings.failed_reports_bucket, | ||
| Key=report_id, | ||
| Key=s3_key, | ||
| ) | ||
| except Exception as exc: | ||
| log.error(f"Unable to upload measurement to s3. Error: {exc}") | ||
| Metrics.SEND_S3_FAILURE.inc() | ||
|
|
||
| log.error(f"Unable to send report to fastpath. report_id: {report_id}") | ||
| log.error(f"Unable to send report to fastpath. measurement_uid: {msmt_uid}") | ||
| Metrics.MISSED_MSMNTS.inc() | ||
| return SubmitMeasurementResponse( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to return to the caller the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the But I agree it wouldn't hurt to have add it
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Norbel suggested that we keep the |
||
| measurement_uid=msmt_uid, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can do this, because it will otherwise result in an inconsistency between what is inside of the measurement already (that the user got through other means) and what we are replacing it with.
In this code path, I think we should be using the
report_idthat's taken from the URL.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do this, we would still have to require the client to make a call to the generate report id function (or change it to generate the
report_idon its own?). Which is fine, but we would only remove thereport_idrequirement from the anonc endpoint and not from the legacy one. Is this what we want?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
/report/{report_id}API call already assumes this as the report_id is encoded inside of the URL path and it cannot work without it: https://github.com/ooni/backend/pull/1195/changes#diff-fd68970e397912b47cad3b7957ef7c811249f632e065d349a0161f06fa516591R103.I don't think we can get rid of requiring the
report_idin a way that's backward compatible.