Last commit july 5th

This commit is contained in:
2024-07-05 13:46:23 +02:00
parent dad0d86e8c
commit b0e4dfbb76
24982 changed files with 2621219 additions and 413 deletions

2
spa/node_modules/sigstore/dist/tlog/verify/body.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { Bundle, TransparencyLogEntry } from '@sigstore/bundle';
export declare function verifyTLogBody(entry: TransparencyLogEntry, bundleContent: Bundle['content']): boolean;

152
spa/node_modules/sigstore/dist/tlog/verify/body.js generated vendored Normal file
View File

@@ -0,0 +1,152 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyTLogBody = void 0;
/*
Copyright 2023 The Sigstore Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const error_1 = require("../../error");
const util_1 = require("../../util");
const TLOG_MISMATCH_ERROR_MSG = 'bundle content and tlog entry do not match';
// Compare the given tlog entry to the given bundle
function verifyTLogBody(entry, bundleContent) {
const { kind, version } = entry.kindVersion;
const body = JSON.parse(entry.canonicalizedBody.toString('utf8'));
try {
if (kind !== body.kind || version !== body.apiVersion) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
switch (body.kind) {
case 'dsse':
verifyDSSETLogBody(body, bundleContent);
break;
case 'intoto':
verifyIntotoTLogBody(body, bundleContent);
break;
case 'hashedrekord':
verifyHashedRekordTLogBody(body, bundleContent);
break;
default:
throw new error_1.VerificationError(`unsupported kind in tlog entry: ${kind}`);
}
return true;
}
catch (e) {
return false;
}
}
exports.verifyTLogBody = verifyTLogBody;
// Compare the given intoto tlog entry to the given bundle
function verifyDSSETLogBody(tlogEntry, content) {
if (content?.$case !== 'dsseEnvelope') {
throw new error_1.VerificationError(`unsupported bundle content: ${content?.$case || 'unknown'}`);
}
const dsse = content.dsseEnvelope;
switch (tlogEntry.apiVersion) {
case '0.0.1':
verifyDSSE001TLogBody(tlogEntry, dsse);
break;
default:
throw new error_1.VerificationError(`unsupported dsse version: ${tlogEntry.apiVersion}`);
}
}
// Compare the given intoto tlog entry to the given bundle
function verifyIntotoTLogBody(tlogEntry, content) {
if (content?.$case !== 'dsseEnvelope') {
throw new error_1.VerificationError(`unsupported bundle content: ${content?.$case || 'unknown'}`);
}
const dsse = content.dsseEnvelope;
switch (tlogEntry.apiVersion) {
case '0.0.2':
verifyIntoto002TLogBody(tlogEntry, dsse);
break;
default:
throw new error_1.VerificationError(`unsupported intoto version: ${tlogEntry.apiVersion}`);
}
}
// Compare the given hashedrekord tlog entry to the given bundle
function verifyHashedRekordTLogBody(tlogEntry, content) {
if (content?.$case !== 'messageSignature') {
throw new error_1.VerificationError(`unsupported bundle content: ${content?.$case || 'unknown'}`);
}
const messageSignature = content.messageSignature;
switch (tlogEntry.apiVersion) {
case '0.0.1':
verifyHashedrekor001TLogBody(tlogEntry, messageSignature);
break;
default:
throw new error_1.VerificationError(`unsupported hashedrekord version: ${tlogEntry.apiVersion}`);
}
}
// Compare the given dsse v0.0.1 tlog entry to the given DSSE envelope.
function verifyDSSE001TLogBody(tlogEntry, dsse) {
// Collect all of the signatures from the DSSE envelope
// Turns them into base64-encoded strings for comparison
const dsseSigs = dsse.signatures.map((signature) => signature.sig.toString('base64'));
// Collect all of the signatures from the tlog entry
const tlogSigs = tlogEntry.spec.signatures?.map((signature) => signature.signature);
// Ensure the bundle's DSSE and the tlog entry contain the same number of signatures
if (dsseSigs.length !== tlogSigs?.length) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure that every signature in the bundle's DSSE is present in the tlog entry
if (!dsseSigs.every((dsseSig) => tlogSigs.includes(dsseSig))) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure the digest of the bundle's DSSE payload matches the digest in the
// tlog entry
const dssePayloadHash = util_1.crypto.hash(dsse.payload).toString('hex');
if (dssePayloadHash !== tlogEntry.spec.payloadHash?.value) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
}
// Compare the given intoto v0.0.2 tlog entry to the given DSSE envelope.
function verifyIntoto002TLogBody(tlogEntry, dsse) {
// Collect all of the signatures from the DSSE envelope
// Turns them into base64-encoded strings for comparison
const dsseSigs = dsse.signatures.map((signature) => signature.sig.toString('base64'));
// Collect all of the signatures from the tlog entry
// Remember that tlog signastures are double base64-encoded
const tlogSigs = tlogEntry.spec.content.envelope?.signatures.map((signature) => (signature.sig ? util_1.encoding.base64Decode(signature.sig) : ''));
// Ensure the bundle's DSSE and the tlog entry contain the same number of signatures
if (dsseSigs.length !== tlogSigs?.length) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure that every signature in the bundle's DSSE is present in the tlog entry
if (!dsseSigs.every((dsseSig) => tlogSigs.includes(dsseSig))) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure the digest of the bundle's DSSE payload matches the digest in the
// tlog entry
const dssePayloadHash = util_1.crypto.hash(dsse.payload).toString('hex');
if (dssePayloadHash !== tlogEntry.spec.content.payloadHash?.value) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
}
// Compare the given hashedrekord v0.0.1 tlog entry to the given message
// signature
function verifyHashedrekor001TLogBody(tlogEntry, messageSignature) {
// Ensure that the bundles message signature matches the tlog entry
const msgSig = messageSignature.signature.toString('base64');
const tlogSig = tlogEntry.spec.signature.content;
if (msgSig !== tlogSig) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure that the bundle's message digest matches the tlog entry
const msgDigest = messageSignature.messageDigest?.digest.toString('hex');
const tlogDigest = tlogEntry.spec.data.hash?.value;
if (msgDigest !== tlogDigest) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
}

View File

@@ -0,0 +1,3 @@
import type { TLogEntryWithInclusionProof } from '@sigstore/bundle';
import * as sigstore from '../../types/sigstore';
export declare function verifyCheckpoint(entry: TLogEntryWithInclusionProof, tlogs: sigstore.TransparencyLogInstance[]): boolean;

View File

@@ -0,0 +1,148 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyCheckpoint = void 0;
const error_1 = require("../../error");
const util_1 = require("../../util");
// Separator between the note and the signatures in a checkpoint
const CHECKPOINT_SEPARATOR = '\n\n';
// Checkpoint signatures are of the following form:
// " <identity> <key_hint+signature_bytes>\n"
// where:
// - the prefix is an emdash (U+2014).
// - <identity> gives a human-readable representation of the signing ID.
// - <key_hint+signature_bytes> is the first 4 bytes of the SHA256 hash of the
// associated public key followed by the signature bytes.
const SIGNATURE_REGEX = /\u2014 (\S+) (\S+)\n/g;
// Verifies the checkpoint value in the given tlog entry. There are two steps
// to the verification:
// 1. Verify that all signatures in the checkpoint can be verified against a
// trusted public key
// 2. Verify that the root hash in the checkpoint matches the root hash in the
// inclusion proof
// See: https://github.com/transparency-dev/formats/blob/main/log/README.md
function verifyCheckpoint(entry, tlogs) {
// Filter tlog instances to just those which were valid at the time of the
// entry
const validTLogs = filterTLogInstances(tlogs, entry.integratedTime);
const inclusionProof = entry.inclusionProof;
const signedNote = SignedNote.fromString(inclusionProof.checkpoint.envelope);
const checkpoint = LogCheckpoint.fromString(signedNote.note);
// Verify that the signatures in the checkpoint are all valid, also check
// that the root hash from the checkpoint matches the root hash in the
// inclusion proof
return (signedNote.verify(validTLogs) &&
util_1.crypto.bufferEqual(checkpoint.logHash, inclusionProof.rootHash));
}
exports.verifyCheckpoint = verifyCheckpoint;
// SignedNote represents a signed note from a transparency log checkpoint. Consists
// of a body (or note) and one more signatures calculated over the body. See
// https://github.com/transparency-dev/formats/blob/main/log/README.md#signed-envelope
class SignedNote {
constructor(note, signatures) {
this.note = note;
this.signatures = signatures;
}
// Deserialize a SignedNote from a string
static fromString(envelope) {
if (!envelope.includes(CHECKPOINT_SEPARATOR)) {
throw new error_1.VerificationError('malformed checkpoint: no separator');
}
// Split the note into the header and the data portions at the separator
const split = envelope.indexOf(CHECKPOINT_SEPARATOR);
const header = envelope.slice(0, split + 1);
const data = envelope.slice(split + CHECKPOINT_SEPARATOR.length);
// Find all the signature lines in the data portion
const matches = data.matchAll(SIGNATURE_REGEX);
// Parse each of the matched signature lines into the name and signature.
// The first four bytes of the signature are the key hint (should match the
// first four bytes of the log ID), and the rest is the signature itself.
const signatures = Array.from(matches, (match) => {
const [, name, signature] = match;
const sigBytes = Buffer.from(signature, 'base64');
if (sigBytes.length < 5) {
throw new error_1.VerificationError('malformed checkpoint: invalid signature');
}
return {
name,
keyHint: sigBytes.subarray(0, 4),
signature: sigBytes.subarray(4),
};
});
if (signatures.length === 0) {
throw new error_1.VerificationError('malformed checkpoint: no signatures');
}
return new SignedNote(header, signatures);
}
// Verifies the signatures in the SignedNote. For each signature, the
// corresponding transparency log is looked up by the key hint and the
// signature is verified against the public key in the transparency log.
// Throws an error if any of the signatures are invalid.
verify(tlogs) {
const data = Buffer.from(this.note, 'utf-8');
return this.signatures.every((signature) => {
// Find the transparency log instance with the matching key hint
const tlog = tlogs.find((tlog) => util_1.crypto.bufferEqual(tlog.logId.keyId.subarray(0, 4), signature.keyHint));
if (!tlog) {
return false;
}
const publicKey = util_1.crypto.createPublicKey(tlog.publicKey.rawBytes);
return util_1.crypto.verifyBlob(data, publicKey, signature.signature);
});
}
}
// LogCheckpoint represents a transparency log checkpoint. Consists of the
// following:
// - origin: the name of the transparency log
// - logSize: the size of the log at the time of the checkpoint
// - logHash: the root hash of the log at the time of the checkpoint
// - rest: the rest of the checkpoint body, which is a list of log entries
// See:
// https://github.com/transparency-dev/formats/blob/main/log/README.md#checkpoint-body
class LogCheckpoint {
constructor(origin, logSize, logHash, rest) {
this.origin = origin;
this.logSize = logSize;
this.logHash = logHash;
this.rest = rest;
}
static fromString(note) {
const lines = note.trim().split('\n');
if (lines.length < 4) {
throw new error_1.VerificationError('malformed checkpoint: too few lines in header');
}
const origin = lines[0];
const logSize = BigInt(lines[1]);
const rootHash = Buffer.from(lines[2], 'base64');
const rest = lines.slice(3);
return new LogCheckpoint(origin, logSize, rootHash, rest);
}
}
// Filter the list of tlog instances to only those which have usable public
// keys and were valid at the given time.
function filterTLogInstances(tlogInstances, integratedTime) {
const targetDate = new Date(Number(integratedTime) * 1000);
return tlogInstances.filter((tlog) => {
// Must have a log ID
if (!tlog.logId) {
return false;
}
// If the tlog doesn't have a public key, we can't use it
const publicKey = tlog.publicKey;
if (publicKey === undefined) {
return false;
}
// If the tlog doesn't have a rawBytes field, we can't use it
if (publicKey.rawBytes === undefined) {
return false;
}
// If the tlog doesn't have a validFor field, we don't need to check it
const validFor = publicKey.validFor;
if (validFor === undefined) {
return true;
}
// Check that the integrated time is within the validFor range
return (validFor.start !== undefined &&
validFor.start <= targetDate &&
(validFor.end === undefined || targetDate <= validFor.end));
});
}

View File

@@ -0,0 +1,3 @@
import { Bundle } from '@sigstore/bundle';
import * as sigstore from '../../types/sigstore';
export declare function verifyTLogEntries(bundle: Bundle, trustedRoot: sigstore.TrustedRoot, options: sigstore.ArtifactVerificationOptions_TlogOptions): void;

92
spa/node_modules/sigstore/dist/tlog/verify/index.js generated vendored Normal file
View File

@@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyTLogEntries = void 0;
/*
Copyright 2023 The Sigstore Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const bundle_1 = require("@sigstore/bundle");
const error_1 = require("../../error");
const cert_1 = require("../../x509/cert");
const body_1 = require("./body");
const checkpoint_1 = require("./checkpoint");
const merkle_1 = require("./merkle");
const set_1 = require("./set");
// Verifies that the number of tlog entries that pass offline verification
// is greater than or equal to the threshold specified in the options.
function verifyTLogEntries(bundle, trustedRoot, options) {
if (bundle.mediaType === bundle_1.BUNDLE_V01_MEDIA_TYPE) {
(0, bundle_1.assertBundleV01)(bundle);
verifyTLogEntriesForBundleV01(bundle, trustedRoot, options);
}
else {
(0, bundle_1.assertBundleLatest)(bundle);
verifyTLogEntriesForBundleLatest(bundle, trustedRoot, options);
}
}
exports.verifyTLogEntries = verifyTLogEntries;
function verifyTLogEntriesForBundleV01(bundle, trustedRoot, options) {
if (options.performOnlineVerification) {
throw new error_1.VerificationError('Online verification not implemented');
}
// Extract the signing cert, if available
const signingCert = signingCertificate(bundle);
// Iterate over the tlog entries and verify each one
const verifiedEntries = bundle.verificationMaterial.tlogEntries.filter((entry) => verifyTLogEntryWithInclusionPromise(entry, bundle.content, trustedRoot.tlogs, signingCert));
if (verifiedEntries.length < options.threshold) {
throw new error_1.VerificationError('tlog verification failed');
}
}
function verifyTLogEntriesForBundleLatest(bundle, trustedRoot, options) {
if (options.performOnlineVerification) {
throw new error_1.VerificationError('Online verification not implemented');
}
// Extract the signing cert, if available
const signingCert = signingCertificate(bundle);
// Iterate over the tlog entries and verify each one
const verifiedEntries = bundle.verificationMaterial.tlogEntries.filter((entry) => verifyTLogEntryWithInclusionProof(entry, bundle.content, trustedRoot.tlogs, signingCert));
if (verifiedEntries.length < options.threshold) {
throw new error_1.VerificationError('tlog verification failed');
}
}
function verifyTLogEntryWithInclusionPromise(entry, bundleContent, tlogs, signingCert) {
// If there is a signing certificate availble, check that the tlog integrated
// time is within the certificate's validity period; otherwise, skip this
// check.
const verifyTLogIntegrationTime = signingCert
? () => signingCert.validForDate(new Date(Number(entry.integratedTime) * 1000))
: () => true;
return ((0, body_1.verifyTLogBody)(entry, bundleContent) &&
(0, set_1.verifyTLogSET)(entry, tlogs) &&
verifyTLogIntegrationTime());
}
function verifyTLogEntryWithInclusionProof(entry, bundleContent, tlogs, signingCert) {
// If there is a signing certificate availble, check that the tlog integrated
// time is within the certificate's validity period; otherwise, skip this
// check.
const verifyTLogIntegrationTime = signingCert
? () => signingCert.validForDate(new Date(Number(entry.integratedTime) * 1000))
: () => true;
return ((0, body_1.verifyTLogBody)(entry, bundleContent) &&
(0, merkle_1.verifyMerkleInclusion)(entry) &&
(0, checkpoint_1.verifyCheckpoint)(entry, tlogs) &&
verifyTLogIntegrationTime());
}
function signingCertificate(bundle) {
if (!(0, bundle_1.isBundleWithCertificateChain)(bundle)) {
return undefined;
}
const signingCert = bundle.verificationMaterial.content.x509CertificateChain.certificates[0];
return cert_1.x509Certificate.parse(signingCert.rawBytes);
}

View File

@@ -0,0 +1,2 @@
import type { TLogEntryWithInclusionProof } from '@sigstore/bundle';
export declare function verifyMerkleInclusion(entry: TLogEntryWithInclusionProof): boolean;

113
spa/node_modules/sigstore/dist/tlog/verify/merkle.js generated vendored Normal file
View File

@@ -0,0 +1,113 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyMerkleInclusion = void 0;
/*
Copyright 2023 The Sigstore Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const crypto_1 = __importDefault(require("crypto"));
const error_1 = require("../../error");
const RFC6962_LEAF_HASH_PREFIX = Buffer.from([0x00]);
const RFC6962_NODE_HASH_PREFIX = Buffer.from([0x01]);
function verifyMerkleInclusion(entry) {
const inclusionProof = entry.inclusionProof;
const logIndex = BigInt(inclusionProof.logIndex);
const treeSize = BigInt(inclusionProof.treeSize);
if (logIndex < 0n || logIndex >= treeSize) {
throw new error_1.VerificationError('invalid inclusion proof index');
}
// Figure out which subset of hashes corresponds to the inner and border
// nodes
const { inner, border } = decompInclProof(logIndex, treeSize);
if (inclusionProof.hashes.length !== inner + border) {
throw new error_1.VerificationError('invalid inclusion proof length');
}
const innerHashes = inclusionProof.hashes.slice(0, inner);
const borderHashes = inclusionProof.hashes.slice(inner);
// The entry's hash is the leaf hash
const leafHash = hashLeaf(entry.canonicalizedBody);
// Chain the hashes belonging to the inner and border portions
const calculatedHash = chainBorderRight(chainInner(leafHash, innerHashes, logIndex), borderHashes);
// Calculated hash should match the root hash in the inclusion proof
return bufferEqual(calculatedHash, inclusionProof.rootHash);
}
exports.verifyMerkleInclusion = verifyMerkleInclusion;
// Breaks down inclusion proof for a leaf at the specified index in a tree of
// the specified size. The split point is where paths to the index leaf and
// the (size - 1) leaf diverge. Returns lengths of the bottom and upper proof
// parts.
function decompInclProof(index, size) {
const inner = innerProofSize(index, size);
const border = onesCount(index >> BigInt(inner));
return { inner, border };
}
// Computes a subtree hash for a node on or below the tree's right border.
// Assumes the provided proof hashes are ordered from lower to higher levels
// and seed is the initial hash of the node specified by the index.
function chainInner(seed, hashes, index) {
return hashes.reduce((acc, h, i) => {
if ((index >> BigInt(i)) & BigInt(1)) {
return hashChildren(h, acc);
}
else {
return hashChildren(acc, h);
}
}, seed);
}
// Computes a subtree hash for nodes along the tree's right border.
function chainBorderRight(seed, hashes) {
return hashes.reduce((acc, h) => hashChildren(h, acc), seed);
}
function innerProofSize(index, size) {
return bitLength(index ^ (size - BigInt(1)));
}
// Counts the number of ones in the binary representation of the given number.
// https://en.wikipedia.org/wiki/Hamming_weight
function onesCount(x) {
return x.toString(2).split('1').length - 1;
}
// Returns the number of bits necessary to represent an integer in binary.
function bitLength(n) {
if (n === 0n) {
return 0;
}
return n.toString(2).length;
}
// Hashing logic according to RFC6962.
// https://datatracker.ietf.org/doc/html/rfc6962#section-2
function hashChildren(left, right) {
const hasher = crypto_1.default.createHash('sha256');
hasher.update(RFC6962_NODE_HASH_PREFIX);
hasher.update(left);
hasher.update(right);
return hasher.digest();
}
function hashLeaf(leaf) {
const hasher = crypto_1.default.createHash('sha256');
hasher.update(RFC6962_LEAF_HASH_PREFIX);
hasher.update(leaf);
return hasher.digest();
}
function bufferEqual(a, b) {
try {
return crypto_1.default.timingSafeEqual(a, b);
}
catch {
/* istanbul ignore next */
return false;
}
}

3
spa/node_modules/sigstore/dist/tlog/verify/set.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import * as sigstore from '../../types/sigstore';
import type { TLogEntryWithInclusionPromise } from '@sigstore/bundle';
export declare function verifyTLogSET(entry: TLogEntryWithInclusionPromise, tlogs: sigstore.TransparencyLogInstance[]): boolean;

64
spa/node_modules/sigstore/dist/tlog/verify/set.js generated vendored Normal file
View File

@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyTLogSET = void 0;
const util_1 = require("../../util");
// Verifies the SET for the given entry against the list of trusted
// transparency logs. Returns true if the SET can be verified against at least
// one of the trusted logs; otherwise, returns false.
function verifyTLogSET(entry, tlogs) {
// Filter the list of tlog instances to only those which might be able to
// verify the SET
const validTLogs = filterTLogInstances(tlogs, entry.logId.keyId, entry.integratedTime);
// Check to see if we can verify the SET against any of the valid tlogs
return validTLogs.some((tlog) => {
const publicKey = util_1.crypto.createPublicKey(tlog.publicKey.rawBytes);
// Re-create the original Rekor verification payload
const payload = toVerificationPayload(entry);
// Canonicalize the payload and turn into a buffer for verification
const data = Buffer.from(util_1.json.canonicalize(payload), 'utf8');
// Extract the SET from the tlog entry
const signature = entry.inclusionPromise.signedEntryTimestamp;
return util_1.crypto.verifyBlob(data, publicKey, signature);
});
}
exports.verifyTLogSET = verifyTLogSET;
// Returns a properly formatted "VerificationPayload" for one of the
// transaction log entires in the given bundle which can be used for SET
// verification.
function toVerificationPayload(entry) {
const { integratedTime, logIndex, logId, canonicalizedBody } = entry;
return {
body: canonicalizedBody.toString('base64'),
integratedTime: Number(integratedTime),
logIndex: Number(logIndex),
logID: logId.keyId.toString('hex'),
};
}
// Filter the list of tlog instances to only those which match the given log
// ID and have public keys which are valid for the given integrated time.
function filterTLogInstances(tlogInstances, logID, integratedTime) {
const targetDate = new Date(Number(integratedTime) * 1000);
return tlogInstances.filter((tlog) => {
// If the log IDs don't match, we can't use this tlog
if (!tlog.logId?.keyId.equals(logID)) {
return false;
}
// If the tlog doesn't have a public key, we can't use it
const publicKey = tlog.publicKey;
if (publicKey === undefined) {
return false;
}
// If the tlog doesn't have a rawBytes field, we can't use it
if (publicKey.rawBytes === undefined) {
return false;
}
// If the tlog doesn't have a validFor field, we don't need to check it
if (publicKey.validFor === undefined) {
return true;
}
// Check that the integrated time is within the validFor range
return (publicKey.validFor.start !== undefined &&
publicKey.validFor.start <= targetDate &&
(!publicKey.validFor.end || targetDate <= publicKey.validFor.end));
});
}