Skip to content
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

fix: support hashed content CIP-30 data content which is typically g… #593

Merged
merged 3 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend-services/voting-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies {
runtimeOnly("org.postgresql:postgresql")

implementation("org.cardanofoundation:merkle-tree-java:0.0.7")
implementation("org.cardanofoundation:cip30-data-signature-parser:0.0.11")
implementation("org.cardanofoundation:cip30-data-signature-parser:0.0.12")

implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class Vote extends AbstractTimestampEntity {
private String signature;

@Column(name = "payload", nullable = false, columnDefinition = "text", length = 2048)
@Nullable
@Nullable // TODO remove nullable since payload is now always required
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in future releases, don't wanna do db migration now, too risky and not necessary.

private String payload;

@Column(name = "public_key")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public Either<Problem, LoginResult> login(Web3AuthenticationToken web3Authentica
}

private Either<Problem, LoginEnvelope> unwrapLoginVoteEnvelope(Web3ConcreteDetails concreteDetails) {
val jsonBody = concreteDetails.getSignedJson();
val jsonBody = concreteDetails.getPayload();

val jsonPayloadE = jsonService.decodeCIP93LoginEnvelope(jsonBody);
if (jsonPayloadE.isLeft()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class CardanoWeb3Details implements Web3ConcreteDetails {
private Cip30VerificationResult cip30VerificationResult;
private CIP93Envelope<Map<String, Object>> envelope;
private SignedCIP30 signedCIP30;
private String payload;

public String getUri() {
return envelope.getUri();
Expand All @@ -40,8 +41,12 @@ public String getSignature() {
return signedCIP30.getSignature();
}

public Optional<String> getPayload() {
return Optional.empty();
public String getPayload() {
if (cip30VerificationResult.isHashed()) {
return payload;
}

return cip30VerificationResult.getMessage(MessageFormat.TEXT);
}

public Optional<String> getPublicKey() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
import java.util.List;
import java.util.Optional;

import static com.bloxbean.cardano.client.crypto.Blake2bUtil.blake2bHash224;
import static com.bloxbean.cardano.client.util.HexUtil.decodeHexString;
import static com.bloxbean.cardano.client.util.HexUtil.encodeHexString;
import static org.cardano.foundation.voting.domain.Role.VOTER;
import static org.cardano.foundation.voting.domain.web3.WalletType.CARDANO;
import static org.cardano.foundation.voting.resource.Headers.X_Ballot_PublicKey;
import static org.cardano.foundation.voting.resource.Headers.X_Ballot_Signature;
import static org.cardano.foundation.voting.resource.Headers.*;
import static org.cardano.foundation.voting.service.auth.LoginSystem.CARDANO_CIP93;
import static org.cardano.foundation.voting.service.auth.web3.MoreFilters.sendBackProblem;
import static org.cardano.foundation.voting.utils.MoreNumber.isNumeric;
Expand Down Expand Up @@ -77,6 +79,7 @@ protected void doFilterInternal(HttpServletRequest req,

val signatureM = Optional.ofNullable(req.getHeader(X_Ballot_Signature));
val publicKey = req.getHeader(X_Ballot_PublicKey);
val payloadM = Optional.ofNullable(req.getHeader(X_Ballot_Payload));

if (signatureM.isEmpty()) {
val problem = Problem.builder()
Expand Down Expand Up @@ -122,7 +125,37 @@ protected void doFilterInternal(HttpServletRequest req,

val walletId = maybeAddress.orElseThrow();

val cipBody = cipVerificationResult.getMessage(MessageFormat.TEXT);
var cipBody = cipVerificationResult.getMessage(MessageFormat.TEXT);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because i saw this: a cose_sign1 signature/structure is still valid even without a payload embedded. not sure how often this is used, but the requesting process already know the payload, so there is no 100% need to have a payload included.

if (cipVerificationResult.isHashed() && payloadM.isEmpty()) {
val problem = Problem.builder()
.withTitle("HASHED_CONTENT_NO_PAYLOAD")
.withDetail("Payload was not sent along with the request and CIP-30 signature contains is hashed!")
.withStatus(BAD_REQUEST)
.build();

sendBackProblem(objectMapper, res, problem);
return;
}

if (cipVerificationResult.isHashed()) {
val cipBodyHash = cipVerificationResult.getMessage(MessageFormat.HEX);
val payload = payloadM.orElseThrow();

val payloadHash = encodeHexString(blake2bHash224(decodeHexString(payload)));

if (!cipBodyHash.equals(payloadHash)) {
val problem = Problem.builder()
.withTitle("CIP_30_HASH_MISMATCH")
.withDetail("Signed hash does not match our precalculated hash!")
.withStatus(BAD_REQUEST)
.build();

sendBackProblem(objectMapper, res, problem);
return;
}

cipBody = new String(decodeHexString(payload)); // flip cipBody to be payload for further processing
}

val cip93EnvelopeE = jsonService.decodeGenericCIP93(cipBody);
if (cip93EnvelopeE.isEmpty()) {
Expand Down Expand Up @@ -318,6 +351,7 @@ protected void doFilterInternal(HttpServletRequest req,
.web3CommonDetails(commonWeb3Details)
.envelope(genericEnvelope)
.signedCIP30(signedWeb3Request)
.payload(cipBody)
.cip30VerificationResult(cipVerificationResult)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public String getSignature() {
}

@Override
public Optional<String> getPayload() {
return Optional.of(signedKERI.getPayload());
public String getPayload() {
return signedKERI.getPayload();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface Web3ConcreteDetails {

String getSignature();

Optional<String> getPayload();
String getPayload();

Optional<String> getPublicKey();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import org.zalando.problem.Problem;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.Objects;

import static com.bloxbean.cardano.client.util.HexUtil.encodeHexString;
import static org.cardano.foundation.voting.domain.VoteReceipt.Status.*;
Expand Down Expand Up @@ -306,7 +306,7 @@ public Either<Problem, Vote> castVote(Web3AuthenticationToken web3Authentication
existingVote.setVotedAtSlot(castVote.getVotedAtSlot());
existingVote.setWalletType(walletType);
existingVote.setSignature(concreteDetails.getSignature());
existingVote.setPayload(concreteDetails.getPayload());
existingVote.setPayload(Optional.of(concreteDetails.getPayload()));
existingVote.setPublicKey(concreteDetails.getPublicKey());

return Either.right(voteRepository.saveAndFlush(existingVote));
Expand All @@ -321,7 +321,7 @@ public Either<Problem, Vote> castVote(Web3AuthenticationToken web3Authentication
vote.setWalletType(walletType);
vote.setVotedAtSlot(castVote.getVotedAtSlot());
vote.setSignature(concreteDetails.getSignature());
vote.setPayload(concreteDetails.getPayload());
vote.setPayload(Optional.of(concreteDetails.getPayload()));
vote.setPublicKey(concreteDetails.getPublicKey());
vote.setIdNumericHash(UUID.fromString(voteId).hashCode() & 0xFFFFFFF);

Expand Down Expand Up @@ -412,7 +412,7 @@ public Either<Problem, Vote> castVote(Web3AuthenticationToken web3Authentication
}

private Either<Problem, ViewVoteReceiptEnvelope> unwrapViewVoteReceiptEnvelope(Web3ConcreteDetails concreteDetails) {
val signedJson = concreteDetails.getSignedJson();
val signedJson = concreteDetails.getPayload();

switch (concreteDetails) {
case CardanoWeb3Details cardanoWeb3Details -> {
Expand Down Expand Up @@ -455,7 +455,7 @@ private Either<Problem, ViewVoteReceiptEnvelope> unwrapViewVoteReceiptEnvelope(W
}

private Either<Problem, VoteEnvelope> unwrapCastCoteEnvelope(Web3ConcreteDetails concreteDetails) {
val signedJson = concreteDetails.getSignedJson();
val signedJson = concreteDetails.getPayload();

switch (concreteDetails) {
case CardanoWeb3Details cardanoWeb3Details -> {
Expand Down
Loading
Loading