@iden3/js-iden3-auth
Version:
iden3-auth implementation in JavaScript
148 lines (147 loc) • 7.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AtomicQueryV3PubSignalsVerifier = void 0;
const ownershipVerifier_1 = require("../circuits/ownershipVerifier");
const common_1 = require("../circuits/common");
const js_iden3_core_1 = require("@iden3/js-iden3-core");
const js_jsonld_merklization_1 = require("@iden3/js-jsonld-merklization");
const js_sdk_1 = require("@0xpolygonid/js-sdk");
const constants_1 = require("../constants");
/**
* Verifies the public signals for the AtomicQueryV3 circuit.
* @beta
*/
class AtomicQueryV3PubSignalsVerifier extends ownershipVerifier_1.IDOwnershipPubSignals {
constructor(pubSignals) {
super();
this.pubSignals = new js_sdk_1.AtomicQueryV3PubSignals();
this.pubSignals = this.pubSignals.pubSignalsUnmarshal(js_sdk_1.byteEncoder.encode(JSON.stringify(pubSignals)));
this.userId = this.pubSignals.userID;
this.challenge = this.pubSignals.requestID;
}
async verifyQuery(query, schemaLoader, verifiablePresentation, opts, params) {
const outs = {
issuerId: this.pubSignals.issuerID,
schemaHash: this.pubSignals.claimSchema,
slotIndex: this.pubSignals.slotIndex,
operator: this.pubSignals.operator,
value: this.pubSignals.value,
timestamp: this.pubSignals.timestamp,
merklized: this.pubSignals.merklized,
claimPathKey: this.pubSignals.claimPathKey,
valueArraySize: constants_1.CONSTANTS.CIRCUITS_ARRAY_VALUE_SIZE,
isRevocationChecked: this.pubSignals.isRevocationChecked,
operatorOutput: this.pubSignals.operatorOutput
};
if (!query.type) {
throw new Error(`proof query type is undefined`);
}
const loader = schemaLoader ?? (0, js_jsonld_merklization_1.getDocumentLoader)();
// validate schema
let context;
try {
context = (await loader(query.context ?? '')).document;
}
catch (e) {
throw new Error(`can't load schema for request query`);
}
const queriesMetadata = await (0, js_sdk_1.parseQueriesMetadata)(query.type, JSON.stringify(context), query.credentialSubject, {
documentLoader: loader
});
const circuitId = js_sdk_1.CircuitId.AtomicQueryV3;
await (0, js_sdk_1.checkQueryRequest)(query, queriesMetadata, context, outs, js_sdk_1.CircuitId.AtomicQueryV3, loader, opts);
const queryMetadata = queriesMetadata[0]; // only one query is supported
(0, js_sdk_1.checkCircuitOperator)(circuitId, outs.operator);
// validate selective disclosure
if (queryMetadata.operator === js_sdk_1.Operators.SD) {
try {
await (0, js_sdk_1.validateDisclosureNativeSDSupport)(queryMetadata, outs, verifiablePresentation, loader);
}
catch (e) {
throw new Error(`failed to validate selective disclosure: ${e.message}`);
}
}
else if (!queryMetadata.fieldName && queryMetadata.operator == js_sdk_1.Operators.NOOP) {
try {
await (0, js_sdk_1.validateEmptyCredentialSubjectNoopNativeSupport)(outs);
}
catch (e) {
throw new Error(`failed to validate operators: ${e.message}`);
}
}
else {
try {
await (0, js_sdk_1.validateOperators)(queryMetadata, outs);
}
catch (e) {
throw new Error(`failed to validate operators: ${e.message}`);
}
}
// verify field inclusion / non-inclusion
(0, js_sdk_1.verifyFieldValueInclusionNativeExistsSupport)(outs, queryMetadata);
const { proofType, verifierID, nullifier, nullifierSessionID, linkID } = this.pubSignals;
switch (query.proofType) {
case js_sdk_1.ProofType.BJJSignature:
if (proofType !== 1) {
throw new Error('wrong proof type for BJJSignature');
}
break;
case js_sdk_1.ProofType.Iden3SparseMerkleTreeProof:
if (proofType !== 2) {
throw new Error('wrong proof type for Iden3SparseMerkleTreeProof');
}
break;
default:
// if proof type is not specified in query any proof type in signals is OK.
}
const nSessionId = BigInt(params?.nullifierSessionId ?? 0);
if (nSessionId !== 0n) {
if (BigInt(nullifier ?? 0) === 0n) {
throw new Error('nullifier should be provided for nullification and should not be 0');
}
// verify nullifier information
const verifierDIDParam = params?.verifierDid;
if (!verifierDIDParam) {
throw new Error('verifierDid is required');
}
const id = js_iden3_core_1.DID.idFromDID(verifierDIDParam);
if (verifierID.bigInt() != id.bigInt()) {
throw new Error('wrong verifier is used for nullification');
}
if (nullifierSessionID !== nSessionId) {
throw new Error(`wrong verifier session id is used for nullification, expected ${nSessionId}, got ${nullifierSessionID}`);
}
}
else if (nullifierSessionID !== 0n) {
throw new Error(`Nullifier id is generated but wasn't requested`);
}
if (!query.groupId && linkID !== 0n) {
throw new Error(`proof contains link id, but group id is not provided`);
}
if (query.groupId && linkID === 0n) {
throw new Error("proof doesn't contain link id, but group id is provided");
}
return this.pubSignals;
}
async verifyStates(resolvers, opts) {
const resolver = (0, common_1.getResolverByID)(resolvers, this.pubSignals.issuerID);
if (!resolver) {
throw new Error(`resolver not found for issuerID ${this.pubSignals.issuerID.string()}`);
}
await (0, common_1.checkUserState)(resolver, this.pubSignals.issuerID, this.pubSignals.issuerState);
if (this.pubSignals.isRevocationChecked === 0) {
return;
}
const issuerNonRevStateResolved = await (0, common_1.checkIssuerNonRevState)(resolver, this.pubSignals.issuerID, this.pubSignals.issuerClaimNonRevState);
const acceptedStateTransitionDelay = opts?.acceptedStateTransitionDelay ?? constants_1.CONSTANTS.ACCEPTED_STATE_TRANSITION_DELAY;
if (issuerNonRevStateResolved.latest) {
return;
}
const timeDiff = Date.now() -
(0, js_iden3_core_1.getDateFromUnixTimestamp)(Number(issuerNonRevStateResolved.transitionTimestamp)).getTime();
if (timeDiff > acceptedStateTransitionDelay) {
throw new Error('issuer state is outdated');
}
}
}
exports.AtomicQueryV3PubSignalsVerifier = AtomicQueryV3PubSignalsVerifier;