export function putEvent()

in src/governance/ccf-app/js/src/endpoints/events.ts [227:329]


export function putEvent(
  request: ccfapp.Request<PutEventRequest>
): ccfapp.Response {
  const body = request.body.json();
  if (!body.attestation) {
    return {
      statusCode: 400,
      body: new ErrorResponse(
        "AttestationMissing",
        "Attestation payload must be supplied."
      )
    };
  }

  if (!body.sign) {
    return {
      statusCode: 400,
      body: new ErrorResponse(
        "SignatureMissing",
        "Signature payload must be supplied."
      )
    };
  }

  if (!body.timestamp) {
    return {
      statusCode: 400,
      body: new ErrorResponse("TimestampMissing", "Timestamp must be supplied.")
    };
  }

  // Similar logic below (but milliseconds instead of seconds) as created_at parameter value for
  // CCF governance proposals.
  // timestamp, submitted as a integer number of milliseconds since epoch, is converted to a
  // decimal representation in ASCII, stored as a string, and
  // compared alphanumerically. This is partly to keep governance as
  // text-based as possible, to facilitate audit, but also to be able
  // to benefit from future planned ordering support in the KV. To
  // compare correctly, the string representation needs to be padded
  // with leading zeroes, and must therefore not exceed a fixed
  // digit width. 13 digits is enough to last until November 2286,
  // ie. long enough.
  const timestampNumber = Number(body.timestamp);
  if (timestampNumber > 9999999999999) {
    return {
      statusCode: 400,
      body: new ErrorResponse(
        "TimestampTooLarge",
        "Timestamp value is too large."
      )
    };
  }

  // First validate attestation report.
  const contractId = request.params.contractId;
  let snpAttestationResult: SnpAttestationResult;
  try {
    snpAttestationResult = verifySnpAttestation(contractId, body.attestation);
  } catch (e) {
    return {
      statusCode: 400,
      body: new ErrorResponse("VerifySnpAttestationFailed", e.message)
    };
  }

  //  Then validate the report data value.
  try {
    verifyReportData(snpAttestationResult, body.sign.publicKey);
  } catch (e) {
    return {
      statusCode: 400,
      body: new ErrorResponse("ReportDataMismatch", e.message)
    };
  }

  // Attestation report and report data values are verified. Now check the signature.
  const data: ArrayBuffer = b64ToBuf(body.data);
  try {
    verifySignature(body.sign, data);
  } catch (e) {
    return {
      statusCode: 400,
      body: new ErrorResponse("SignatureMismatch", e.message)
    };
  }

  // All verifications pass. Now insert the event.
  const parsedQuery = parseRequestQuery(request);
  const id = getIdFromQuery(parsedQuery, contractId);
  const { scope } = parsedQuery;
  const eventsMap = ccfapp.typedKv(
    getEventsMapName(contractId, scope),
    ccfapp.string,
    ccfapp.json<EventStoreItem>()
  );

  const jsonObject = JSON.parse(ccf.bufToStr(data));
  const timestamp = body.timestamp.padStart(13, "0");
  eventsMap.set(id, { timestamp: timestamp, data: jsonObject });
  return {
    statusCode: 204
  };
}