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 +9 -0
- package/README.md +10 -2
- package/dist/core/revocation/crl.d.ts +1 -0
- package/dist/core/revocation/fetch.d.ts +12 -3
- package/dist/core/revocation/ocsp.d.ts +3 -1
- package/dist/core/revocation/types.d.ts +8 -1
- package/dist/index.cjs.js +23 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +23 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +10 -10
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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:
|
|
@@ -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(
|
|
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") {
|