edockit 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2025-12-30
9
+
10
+ ### Added
11
+
12
+ - **CORS Proxy Support** - New `proxyUrl` option in `revocationOptions` for browser environments
13
+ - Routes OCSP, CRL, and CA issuer certificate requests through a CORS proxy
14
+ - Enables revocation checking in browsers where direct requests are blocked by CORS
15
+
8
16
  ## [0.2.0] - 2025-12-29
9
17
 
10
18
  ### Added
@@ -39,5 +47,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
39
47
  - File checksum verification (SHA-256/384/512)
40
48
  - Browser and Node.js support
41
49
 
50
+ [0.2.1]: https://github.com/edgarsj/edockit/compare/v0.2.0...v0.2.1
42
51
  [0.2.0]: https://github.com/edgarsj/edockit/compare/v0.1.2...v0.2.0
43
52
  [0.1.2]: https://github.com/edgarsj/edockit/releases/tag/v0.1.2
package/README.md CHANGED
@@ -45,6 +45,7 @@ const result = await verifySignature(container.signatures[0], container.files, {
45
45
  revocationOptions: { // Optional: configure revocation check behavior
46
46
  ocspTimeout: 5000, // OCSP request timeout in ms (default: 5000)
47
47
  crlTimeout: 10000, // CRL fetch timeout in ms (default: 10000)
48
+ proxyUrl: 'https://cors-proxy.example.com/?url=', // CORS proxy for browser (optional)
48
49
  },
49
50
  verifyTimestamps: true, // RFC 3161 timestamp verification (default: true)
50
51
  verifyTime: new Date() // Verify certificate at specific time (default: timestamp time if present, otherwise now)
@@ -119,8 +120,13 @@ async function verifyDocument(url) {
119
120
  console.log("Documents:", container.documentFileList);
120
121
 
121
122
  for (const signature of container.signatures) {
122
- const result = await verifySignature(signature, container.files);
123
- // checkRevocation and verifyTimestamps default to true
123
+ const result = await verifySignature(signature, container.files, {
124
+ checkRevocation: true,
125
+ revocationOptions: {
126
+ // Use a CORS proxy for OCSP/CRL requests in browser environments
127
+ proxyUrl: 'https://your-cors-proxy.example.com/?url=',
128
+ },
129
+ });
124
130
 
125
131
  console.log(`Valid: ${result.isValid}`);
126
132
 
@@ -134,6 +140,8 @@ async function verifyDocument(url) {
134
140
  }
135
141
  ```
136
142
 
143
+ > **Note:** OCSP and CRL endpoints typically don't support CORS, so browser environments need a proxy to perform revocation checks. The `proxyUrl` option routes all revocation requests through the specified proxy, which should accept the original URL as a query parameter.
144
+
137
145
  ### Timestamp Utilities
138
146
 
139
147
  For advanced timestamp handling, you can use the timestamp utilities directly:
@@ -31,4 +31,5 @@ export declare function parseCRL(data: ArrayBuffer): X509Crl | null;
31
31
  */
32
32
  export declare function checkCRL(cert: X509Certificate, options?: {
33
33
  timeout?: number;
34
+ proxyUrl?: string;
34
35
  }): Promise<RevocationResult>;
@@ -13,6 +13,12 @@ export interface FetchOptions {
13
13
  contentType?: string;
14
14
  /** Accept header */
15
15
  accept?: string;
16
+ /**
17
+ * CORS proxy URL for browser environments.
18
+ * When set, the original URL will be URL-encoded and appended to this proxy URL.
19
+ * Example: "https://cors-proxy.example.com/?url="
20
+ */
21
+ proxyUrl?: string;
16
22
  }
17
23
  export interface FetchResult {
18
24
  ok: boolean;
@@ -32,20 +38,23 @@ export declare function fetchBinary(url: string, options?: FetchOptions): Promis
32
38
  * @param url OCSP responder URL
33
39
  * @param request DER-encoded OCSP request
34
40
  * @param timeout Timeout in milliseconds
41
+ * @param proxyUrl Optional CORS proxy URL
35
42
  * @returns FetchResult with OCSP response data
36
43
  */
37
- export declare function fetchOCSP(url: string, request: ArrayBuffer, timeout?: number): Promise<FetchResult>;
44
+ export declare function fetchOCSP(url: string, request: ArrayBuffer, timeout?: number, proxyUrl?: string): Promise<FetchResult>;
38
45
  /**
39
46
  * Fetch CRL from distribution point
40
47
  * @param url CRL distribution point URL
41
48
  * @param timeout Timeout in milliseconds
49
+ * @param proxyUrl Optional CORS proxy URL
42
50
  * @returns FetchResult with CRL data
43
51
  */
44
- export declare function fetchCRL(url: string, timeout?: number): Promise<FetchResult>;
52
+ export declare function fetchCRL(url: string, timeout?: number, proxyUrl?: string): Promise<FetchResult>;
45
53
  /**
46
54
  * Fetch issuer certificate from AIA extension
47
55
  * @param url CA Issuers URL
48
56
  * @param timeout Timeout in milliseconds
57
+ * @param proxyUrl Optional CORS proxy URL
49
58
  * @returns FetchResult with certificate data
50
59
  */
51
- export declare function fetchIssuerCertificate(url: string, timeout?: number): Promise<FetchResult>;
60
+ export declare function fetchIssuerCertificate(url: string, timeout?: number, proxyUrl?: string): Promise<FetchResult>;
@@ -23,9 +23,10 @@ export declare function findIssuerInChain(cert: X509Certificate, chain: string[]
23
23
  * Fetch issuer certificate from AIA extension
24
24
  * @param cert Certificate to fetch issuer for
25
25
  * @param timeout Timeout in ms
26
+ * @param proxyUrl Optional CORS proxy URL
26
27
  * @returns Issuer certificate or null
27
28
  */
28
- export declare function fetchIssuerFromAIA(cert: X509Certificate, timeout?: number): Promise<X509Certificate | null>;
29
+ export declare function fetchIssuerFromAIA(cert: X509Certificate, timeout?: number, proxyUrl?: string): Promise<X509Certificate | null>;
29
30
  /**
30
31
  * Build OCSP request for a certificate
31
32
  * @param cert Certificate to check
@@ -49,4 +50,5 @@ export declare function parseOCSPResponse(responseData: ArrayBuffer): Revocation
49
50
  export declare function checkOCSP(cert: X509Certificate, issuerCert: X509Certificate | null, options?: {
50
51
  timeout?: number;
51
52
  certificateChain?: string[];
53
+ proxyUrl?: string;
52
54
  }): Promise<RevocationResult>;
@@ -29,11 +29,18 @@ export interface RevocationCheckOptions {
29
29
  crlTimeout?: number;
30
30
  /** Certificate chain for finding issuer (PEM strings) */
31
31
  certificateChain?: string[];
32
+ /**
33
+ * CORS proxy URL for browser environments.
34
+ * When set, all OCSP/CRL fetch requests will be routed through this proxy.
35
+ * The original URL will be URL-encoded and appended as a query parameter.
36
+ * Example: "https://cors-proxy.example.com/?url="
37
+ */
38
+ proxyUrl?: string;
32
39
  }
33
40
  /**
34
41
  * Default options for revocation checking
35
42
  */
36
- export declare const DEFAULT_REVOCATION_OPTIONS: Required<Omit<RevocationCheckOptions, "certificateChain">>;
43
+ export declare const DEFAULT_REVOCATION_OPTIONS: Required<Omit<RevocationCheckOptions, "certificateChain" | "proxyUrl">>;
37
44
  /**
38
45
  * OID constants for certificate extensions
39
46
  */
package/dist/index.cjs.js CHANGED
@@ -7926,7 +7926,9 @@ __decorate([
7926
7926
  * @returns FetchResult with binary data or error
7927
7927
  */
7928
7928
  async function fetchBinary(url, options = {}) {
7929
- const { timeout = 10000, method = "GET", body, contentType, accept } = options;
7929
+ const { timeout = 10000, method = "GET", body, contentType, accept, proxyUrl } = options;
7930
+ // Apply proxy URL if provided
7931
+ const fetchUrl = proxyUrl ? `${proxyUrl}${encodeURIComponent(url)}` : url;
7930
7932
  const controller = new AbortController();
7931
7933
  const timeoutId = setTimeout(() => controller.abort(), timeout);
7932
7934
  try {
@@ -7937,7 +7939,7 @@ async function fetchBinary(url, options = {}) {
7937
7939
  if (accept) {
7938
7940
  headers["Accept"] = accept;
7939
7941
  }
7940
- const response = await fetch(url, {
7942
+ const response = await fetch(fetchUrl, {
7941
7943
  method,
7942
7944
  headers,
7943
7945
  body: body ? new Uint8Array(body) : undefined,
@@ -7986,41 +7988,47 @@ async function fetchBinary(url, options = {}) {
7986
7988
  * @param url OCSP responder URL
7987
7989
  * @param request DER-encoded OCSP request
7988
7990
  * @param timeout Timeout in milliseconds
7991
+ * @param proxyUrl Optional CORS proxy URL
7989
7992
  * @returns FetchResult with OCSP response data
7990
7993
  */
7991
- async function fetchOCSP(url, request, timeout = 5000) {
7994
+ async function fetchOCSP(url, request, timeout = 5000, proxyUrl) {
7992
7995
  return fetchBinary(url, {
7993
7996
  method: "POST",
7994
7997
  body: request,
7995
7998
  contentType: "application/ocsp-request",
7996
7999
  accept: "application/ocsp-response",
7997
8000
  timeout,
8001
+ proxyUrl,
7998
8002
  });
7999
8003
  }
8000
8004
  /**
8001
8005
  * Fetch CRL from distribution point
8002
8006
  * @param url CRL distribution point URL
8003
8007
  * @param timeout Timeout in milliseconds
8008
+ * @param proxyUrl Optional CORS proxy URL
8004
8009
  * @returns FetchResult with CRL data
8005
8010
  */
8006
- async function fetchCRL(url, timeout = 10000) {
8011
+ async function fetchCRL(url, timeout = 10000, proxyUrl) {
8007
8012
  return fetchBinary(url, {
8008
8013
  method: "GET",
8009
8014
  accept: "application/pkix-crl",
8010
8015
  timeout,
8016
+ proxyUrl,
8011
8017
  });
8012
8018
  }
8013
8019
  /**
8014
8020
  * Fetch issuer certificate from AIA extension
8015
8021
  * @param url CA Issuers URL
8016
8022
  * @param timeout Timeout in milliseconds
8023
+ * @param proxyUrl Optional CORS proxy URL
8017
8024
  * @returns FetchResult with certificate data
8018
8025
  */
8019
- async function fetchIssuerCertificate(url, timeout = 5000) {
8026
+ async function fetchIssuerCertificate(url, timeout = 5000, proxyUrl) {
8020
8027
  return fetchBinary(url, {
8021
8028
  method: "GET",
8022
8029
  accept: "application/pkix-cert",
8023
8030
  timeout,
8031
+ proxyUrl,
8024
8032
  });
8025
8033
  }
8026
8034
 
@@ -8177,13 +8185,14 @@ function findIssuerInChain(cert, chain) {
8177
8185
  * Fetch issuer certificate from AIA extension
8178
8186
  * @param cert Certificate to fetch issuer for
8179
8187
  * @param timeout Timeout in ms
8188
+ * @param proxyUrl Optional CORS proxy URL
8180
8189
  * @returns Issuer certificate or null
8181
8190
  */
8182
- async function fetchIssuerFromAIA(cert, timeout = 5000) {
8191
+ async function fetchIssuerFromAIA(cert, timeout = 5000, proxyUrl) {
8183
8192
  const urls = extractCAIssuersUrls(cert);
8184
8193
  for (const url of urls) {
8185
8194
  try {
8186
- const result = await fetchIssuerCertificate(url, timeout);
8195
+ const result = await fetchIssuerCertificate(url, timeout, proxyUrl);
8187
8196
  if (result.ok && result.data) {
8188
8197
  // Try to parse as DER first, then PEM
8189
8198
  try {
@@ -8376,7 +8385,7 @@ function parseOCSPResponse(responseData) {
8376
8385
  * @returns Revocation result
8377
8386
  */
8378
8387
  async function checkOCSP(cert, issuerCert, options = {}) {
8379
- const { timeout = 5000, certificateChain = [] } = options;
8388
+ const { timeout = 5000, certificateChain = [], proxyUrl } = options;
8380
8389
  const now = new Date();
8381
8390
  // Get OCSP URLs
8382
8391
  const ocspUrls = extractOCSPUrls(cert);
@@ -8397,7 +8406,7 @@ async function checkOCSP(cert, issuerCert, options = {}) {
8397
8406
  }
8398
8407
  if (!issuer) {
8399
8408
  // Try AIA extension
8400
- issuer = await fetchIssuerFromAIA(cert, timeout);
8409
+ issuer = await fetchIssuerFromAIA(cert, timeout, proxyUrl);
8401
8410
  }
8402
8411
  if (!issuer) {
8403
8412
  return {
@@ -8425,7 +8434,7 @@ async function checkOCSP(cert, issuerCert, options = {}) {
8425
8434
  // Try each OCSP URL
8426
8435
  for (const url of ocspUrls) {
8427
8436
  try {
8428
- const result = await fetchOCSP(url, request, timeout);
8437
+ const result = await fetchOCSP(url, request, timeout, proxyUrl);
8429
8438
  if (result.ok && result.data) {
8430
8439
  return parseOCSPResponse(result.data);
8431
8440
  }
@@ -8532,7 +8541,7 @@ function parseCRL(data) {
8532
8541
  * @returns Revocation result
8533
8542
  */
8534
8543
  async function checkCRL(cert, options = {}) {
8535
- const { timeout = 10000 } = options;
8544
+ const { timeout = 10000, proxyUrl } = options;
8536
8545
  const now = new Date();
8537
8546
  // Get CRL URLs
8538
8547
  const crlUrls = extractCRLUrls(cert);
@@ -8549,7 +8558,7 @@ async function checkCRL(cert, options = {}) {
8549
8558
  const errors = [];
8550
8559
  for (const url of crlUrls) {
8551
8560
  try {
8552
- const result = await fetchCRL(url, timeout);
8561
+ const result = await fetchCRL(url, timeout, proxyUrl);
8553
8562
  if (!result.ok || !result.data) {
8554
8563
  errors.push(`${url}: ${result.error || "Failed to fetch"}`);
8555
8564
  continue;
@@ -8638,6 +8647,7 @@ async function checkCertificateRevocation(cert, options = {}) {
8638
8647
  ocspResult = await checkOCSP(x509Cert, null, {
8639
8648
  timeout: opts.ocspTimeout,
8640
8649
  certificateChain: opts.certificateChain,
8650
+ proxyUrl: options.proxyUrl,
8641
8651
  });
8642
8652
  // If OCSP gives a definitive answer (good or revoked), use it
8643
8653
  if (ocspResult.status === "good" || ocspResult.status === "revoked") {
@@ -8649,6 +8659,7 @@ async function checkCertificateRevocation(cert, options = {}) {
8649
8659
  if (opts.crlEnabled) {
8650
8660
  crlResult = await checkCRL(x509Cert, {
8651
8661
  timeout: opts.crlTimeout,
8662
+ proxyUrl: options.proxyUrl,
8652
8663
  });
8653
8664
  // If CRL gives a definitive answer, use it
8654
8665
  if (crlResult.status === "good" || crlResult.status === "revoked") {