ems-project / elasticms

ElasticMS's monorepo
MIT License
3 stars 8 forks source link

Revision signing & setRawDataFinalizedBy #950

Open Davidmattei opened 3 weeks ago

Davidmattei commented 3 weeks ago

Revision Entity:

public function setRawDataFinalizedBy(string $finalizedBy): self
{
        $this->rawData[Mapping::FINALIZED_BY_FIELD] = $finalizedBy;
        $this->tryToFinalizeOn = new \DateTime();
        $this->rawData[Mapping::FINALIZATION_DATETIME_FIELD] = $this->tryToFinalizeOn->format(\DateTimeInterface::ATOM);

        return $this;
}

public function setFinalizedBy(string $finalizedBy): self
{
        $this->finalizedBy = $finalizedBy;
        $this->finalizedDate = $this->tryToFinalizeOn;

        return $this;
}

dataService:


  public function sign(Revision $revision, bool $silentPublish = false): array
    {
        if ($silentPublish && $revision->getAutoSave()) {
            $objectArray = $revision->getAutoSave();
        } else {
            $objectArray = $revision->getRawData();
        }

        $objectArray[Mapping::CONTENT_TYPE_FIELD] = $revision->giveContentType()->getName();
        if ($revision->hasVersionTags()) {
            $objectArray[Mapping::VERSION_UUID] = $revision->getVersionUuid();
            $objectArray[Mapping::VERSION_TAG] = $revision->getVersionTag();
            $revision->updateVersionNextTag();
        }

        $hash = $this->signRaw($objectArray);
        $revision->setSha1($hash);

        $revision->setRawData($objectArray);

        return $objectArray;
    }

public function signRaw(array &$objectArray): string
{
        if (isset($objectArray[Mapping::HASH_FIELD])) {
            unset($objectArray[Mapping::HASH_FIELD]);
        }
        if (isset($objectArray[Mapping::SIGNATURE_FIELD])) {
            unset($objectArray[Mapping::SIGNATURE_FIELD]);
        }
        if (isset($objectArray[Mapping::PUBLISHED_DATETIME_FIELD])) {
            unset($objectArray[Mapping::PUBLISHED_DATETIME_FIELD]);
        }
        Json::normalize($objectArray);
        $json = Json::encode($objectArray);

        $hash = $this->storageManager->computeStringHash($json);
        $objectArray[Mapping::HASH_FIELD] = $hash;

        //......
}

public function finalizeDraft(Revision $revision, ......)
{
       //......
       $revision->setRawDataFinalizedBy($username);

       $objectArray = $this->sign($revision);

       if ($this->isValid($form, null, $objectArray)) {
            //......

            $revision->setFinalizedBy($username);

            $em->persist($revision);
            $em->flush();
       }

Issues with this code:

Solution:

Davidmattei commented 3 weeks ago

If we change this we can also update the recompute:

We are signing the new revision twice, because we first need to be able to see if something has changed. Setting the finalized by to SYSTEM_RECOMPUTE will allways result in a new revision, see description ticket.

  $revision->close(new \DateTime('now'));
  $newRevision->setDraft(false);

  $this->dataService->sign($revision);
  $this->dataService->sign($newRevision);

  if ($this->isChanged && $revision->getHash() === $newRevision->getHash()) {
      $this->revisionRepository->unlockRevision($revisionId);
      $progress->advance();
      continue;
  }

  $newRevision->setFinalizedBy(self::LOCK_BY);
  $newRevision->setRawDataFinalizedBy(self::LOCK_BY);
  $this->dataService->sign($newRevision);

Should become

  $revision->close(new \DateTime('now'));
  $newRevision->setDraft(false);
  $newRevision->setFinalizedBy(self::LOCK_BY);

  $this->dataService->sign($revision);
  $this->dataService->sign($newRevision);

  if ($this->isChanged && $revision->getHash() === $newRevision->getHash()) {
      $this->revisionRepository->unlockRevision($revisionId);
      $progress->advance();
      continue;
  }
Davidmattei commented 2 weeks ago

Discussed: the signing raw can excluded all fields starting with an underscore. at the root level