handleGetRawDoc returns the raw version of the stored document for diagnostic purposes. It can optionally redact UserData in the sync metadata and allows a custom salt for correlating with collected logs.
()
| 1429 | // handleGetRawDoc returns the raw version of the stored document for diagnostic purposes. |
| 1430 | // It can optionally redact UserData in the sync metadata and allows a custom salt for correlating with collected logs. |
| 1431 | func (h *handler) handleGetRawDoc() error { |
| 1432 | h.assertAdminOnly() |
| 1433 | |
| 1434 | var ( |
| 1435 | docID = h.PathVar("docid") |
| 1436 | includeDoc, includeDocSet = h.getOptBoolQuery("include_doc", true) |
| 1437 | redact = h.getBoolQuery("redact") |
| 1438 | redactSalt = h.getQuery("salt") |
| 1439 | ) |
| 1440 | |
| 1441 | if redact { |
| 1442 | // cannot explicitly include doc and redact - it doesn't make sense since the doc body itself is considered UserData and eligible for redaction. |
| 1443 | if includeDocSet && includeDoc { |
| 1444 | return base.HTTPErrorf(http.StatusBadRequest, "redact and include_doc cannot be true at the same time. "+ |
| 1445 | "If you want to redact you must specify include_doc=false") |
| 1446 | } |
| 1447 | // if include_doc was not explicitly set, and we want to redact, then automatically set include_doc to false |
| 1448 | includeDoc = false |
| 1449 | } else if redactSalt != "" { |
| 1450 | return base.HTTPErrorf(http.StatusBadRequest, "redactSalt can only be used when redact=true") |
| 1451 | } |
| 1452 | |
| 1453 | opts := db.GetRawDocOpts{ |
| 1454 | IncludeDoc: includeDoc, |
| 1455 | Redact: redact, |
| 1456 | RedactSalt: redactSalt, |
| 1457 | } |
| 1458 | docBody, xattrValues, err := h.collection.GetRawDoc(h.ctx(), docID, &opts) |
| 1459 | if err != nil { |
| 1460 | return err |
| 1461 | } |
| 1462 | |
| 1463 | responseBody := []byte(base.EmptyDocument) |
| 1464 | if docBody != nil { |
| 1465 | responseBody = docBody |
| 1466 | } |
| 1467 | |
| 1468 | responseBody, err = base.InjectJSONProperties(responseBody, base.KVPair{Key: "_xattrs", Val: xattrValues}) |
| 1469 | if err != nil { |
| 1470 | return base.HTTPErrorf(http.StatusInternalServerError, "couldn't inject xattrs into response: %s", err) |
| 1471 | } |
| 1472 | |
| 1473 | base.Audit(h.ctx(), base.AuditIDDocumentMetadataRead, base.AuditFields{ |
| 1474 | base.AuditFieldDocID: docID, |
| 1475 | }) |
| 1476 | if includeDoc && base.AuditEventIsEnabled(h.ctx(), base.AuditIDDocumentRead) { |
| 1477 | // best-effort attempt to extract a revision from the raw sync data |
| 1478 | docCurrentRev := "unknown" |
| 1479 | if syncData, ok := xattrValues[base.SyncXattrName]; ok { |
| 1480 | var sdRev struct { |
| 1481 | Rev channels.RevAndVersion `json:"rev"` |
| 1482 | } |
| 1483 | if err := json.Unmarshal(syncData, &sdRev); err != nil { |
| 1484 | // syncData is not normally generally redacted, but in this case we know it's malformed in some way and want the raw data in the log message. |
| 1485 | // This data may contain channel names, etc. which _are_ classed as UserData, so tag the whole thing. |
| 1486 | base.WarnfCtx(h.ctx(), "couldn't unmarshal doc %q SyncData xattr value %q: %s", base.UD(docID), base.UD(syncData), err) |
| 1487 | } else { |
| 1488 | docCurrentRev = sdRev.Rev.RevTreeID |
nothing calls this directly
no test coverage detected