ovsx 1.1.1 → 1.3.0

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.
Files changed (132) hide show
  1. package/README.md +73 -1
  2. package/lib/check-license.d.ts.map +1 -1
  3. package/lib/check-license.js +3 -2
  4. package/lib/check-license.js.map +1 -1
  5. package/lib/get.js +6 -6
  6. package/lib/get.js.map +1 -1
  7. package/lib/http.d.ts +32 -0
  8. package/lib/http.d.ts.map +1 -0
  9. package/lib/http.js +170 -0
  10. package/lib/http.js.map +1 -0
  11. package/lib/index.d.ts +4 -0
  12. package/lib/index.d.ts.map +1 -1
  13. package/lib/index.js +4 -0
  14. package/lib/index.js.map +1 -1
  15. package/lib/list-options.d.ts +24 -0
  16. package/lib/list-options.d.ts.map +1 -0
  17. package/lib/list-options.js +15 -0
  18. package/lib/list-options.js.map +1 -0
  19. package/lib/list.d.ts +18 -0
  20. package/lib/list.d.ts.map +1 -0
  21. package/lib/list.js +46 -0
  22. package/lib/list.js.map +1 -0
  23. package/lib/main.js +111 -32
  24. package/lib/main.js.map +1 -1
  25. package/lib/oidc.d.ts +22 -0
  26. package/lib/oidc.d.ts.map +1 -0
  27. package/lib/oidc.js +59 -0
  28. package/lib/oidc.js.map +1 -0
  29. package/lib/publish-options.d.ts +8 -1
  30. package/lib/publish-options.d.ts.map +1 -1
  31. package/lib/publish.d.ts.map +1 -1
  32. package/lib/publish.js +150 -13
  33. package/lib/publish.js.map +1 -1
  34. package/lib/registry-options.d.ts +8 -0
  35. package/lib/registry-options.d.ts.map +1 -1
  36. package/lib/registry.d.ts +161 -5
  37. package/lib/registry.d.ts.map +1 -1
  38. package/lib/registry.js +259 -100
  39. package/lib/registry.js.map +1 -1
  40. package/lib/search-options.d.ts +48 -0
  41. package/lib/search-options.d.ts.map +1 -0
  42. package/lib/search-options.js +15 -0
  43. package/lib/search-options.js.map +1 -0
  44. package/lib/search.d.ts +22 -0
  45. package/lib/search.d.ts.map +1 -0
  46. package/lib/search.js +86 -0
  47. package/lib/search.js.map +1 -0
  48. package/lib/show-options.d.ts +33 -0
  49. package/lib/show-options.d.ts.map +1 -0
  50. package/lib/show-options.js +15 -0
  51. package/lib/show-options.js.map +1 -0
  52. package/lib/show.d.ts +18 -0
  53. package/lib/show.d.ts.map +1 -0
  54. package/lib/show.js +289 -0
  55. package/lib/show.js.map +1 -0
  56. package/lib/table.d.ts +27 -0
  57. package/lib/table.d.ts.map +1 -0
  58. package/lib/table.js +56 -0
  59. package/lib/table.js.map +1 -0
  60. package/lib/trusted-publishing-options.d.ts +30 -0
  61. package/lib/trusted-publishing-options.d.ts.map +1 -0
  62. package/lib/trusted-publishing-options.js +15 -0
  63. package/lib/trusted-publishing-options.js.map +1 -0
  64. package/lib/trusted-publishing.d.ts +35 -0
  65. package/lib/trusted-publishing.d.ts.map +1 -0
  66. package/lib/trusted-publishing.js +112 -0
  67. package/lib/trusted-publishing.js.map +1 -0
  68. package/lib/unpublish-options.d.ts +34 -0
  69. package/lib/unpublish-options.d.ts.map +1 -0
  70. package/lib/unpublish-options.js +15 -0
  71. package/lib/unpublish-options.js.map +1 -0
  72. package/lib/unpublish.d.ts +22 -0
  73. package/lib/unpublish.d.ts.map +1 -0
  74. package/lib/unpublish.js +137 -0
  75. package/lib/unpublish.js.map +1 -0
  76. package/lib/util.d.ts +51 -9
  77. package/lib/util.d.ts.map +1 -1
  78. package/lib/util.js +130 -67
  79. package/lib/util.js.map +1 -1
  80. package/lib/verify-options.d.ts +24 -0
  81. package/lib/verify-options.d.ts.map +1 -0
  82. package/lib/verify-options.js +15 -0
  83. package/lib/verify-options.js.map +1 -0
  84. package/lib/verify-signature-options.d.ts +32 -0
  85. package/lib/verify-signature-options.d.ts.map +1 -0
  86. package/lib/verify-signature-options.js +15 -0
  87. package/lib/verify-signature-options.js.map +1 -0
  88. package/lib/verify-signature.d.ts +28 -0
  89. package/lib/verify-signature.d.ts.map +1 -0
  90. package/lib/verify-signature.js +105 -0
  91. package/lib/verify-signature.js.map +1 -0
  92. package/lib/verify.d.ts +21 -0
  93. package/lib/verify.d.ts.map +1 -0
  94. package/lib/verify.js +97 -0
  95. package/lib/verify.js.map +1 -0
  96. package/lib/zip.d.ts +10 -0
  97. package/lib/zip.d.ts.map +1 -1
  98. package/lib/zip.js +33 -10
  99. package/lib/zip.js.map +1 -1
  100. package/package.json +21 -14
  101. package/src/check-license.ts +4 -3
  102. package/src/get.ts +7 -7
  103. package/src/http.ts +176 -0
  104. package/src/index.ts +4 -0
  105. package/src/list-options.ts +25 -0
  106. package/src/list.ts +48 -0
  107. package/src/main.ts +125 -34
  108. package/src/oidc.ts +65 -0
  109. package/src/publish-options.ts +8 -1
  110. package/src/publish.ts +208 -14
  111. package/src/registry-options.ts +8 -0
  112. package/src/registry.ts +379 -98
  113. package/src/search-options.ts +49 -0
  114. package/src/search.ts +95 -0
  115. package/src/show-options.ts +34 -0
  116. package/src/show.ts +328 -0
  117. package/src/table.ts +53 -0
  118. package/src/trusted-publishing-options.ts +30 -0
  119. package/src/trusted-publishing.ts +148 -0
  120. package/src/unpublish-options.ts +35 -0
  121. package/src/unpublish.ts +160 -0
  122. package/src/util.ts +138 -70
  123. package/src/verify-options.ts +25 -0
  124. package/src/verify-signature-options.ts +32 -0
  125. package/src/verify-signature.ts +124 -0
  126. package/src/verify.ts +107 -0
  127. package/src/zip.ts +33 -13
  128. package/lib/version.d.ts +0 -2
  129. package/lib/version.d.ts.map +0 -1
  130. package/lib/version.js +0 -5
  131. package/lib/version.js.map +0 -1
  132. package/src/version.ts +0 -1
package/src/verify.ts ADDED
@@ -0,0 +1,107 @@
1
+ /******************************************************************************
2
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
3
+ *
4
+ * See the NOTICE file(s) distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ *
7
+ * This program and the accompanying materials are made available under the
8
+ * terms of the Eclipse Public License 2.0 which is available at
9
+ * https://www.eclipse.org/legal/epl-2.0
10
+ *
11
+ * SPDX-License-Identifier: EPL-2.0
12
+ *****************************************************************************/
13
+
14
+ import * as crypto from 'crypto';
15
+ import * as fs from 'fs';
16
+ import { Registry, Extension } from './registry';
17
+ import { addEnvOptions, getTempFilePath } from './util';
18
+ import { readVSIXPackage, readZip } from './zip';
19
+ import { VerifyOptions } from './verify-options';
20
+
21
+ const SIGNATURE_ENTRY = '.signature.sig';
22
+
23
+ /**
24
+ * Verifies a downloaded .vsix package's signature against the registry's public key, the same way
25
+ * VS Code itself verifies signed packages on install. Mirrors `vsce verify-signature`, except the
26
+ * signature and public key are fetched from the registry instead of being passed in as separate
27
+ * files - the registry already exposes both for any published, signed version.
28
+ */
29
+ export async function verify(options: VerifyOptions): Promise<void> {
30
+ addEnvOptions(options);
31
+ const registry = new Registry(options);
32
+
33
+ const manifest = await readVSIXPackage(options.packagePath);
34
+ const namespace = manifest.publisher;
35
+ const extensionName = manifest.name;
36
+
37
+ const latest = await registry.getMetadata(namespace, extensionName, options.target);
38
+ if (latest.error) {
39
+ throw new Error(latest.error);
40
+ }
41
+
42
+ const extension = await resolveVersion(registry, latest, manifest.version);
43
+ const description = `${namespace}.${extensionName} v${extension.version}`;
44
+
45
+ const signatureUrl = extension.files.signature;
46
+ const publicKeyUrl = extension.files.publicKey;
47
+ if (!signatureUrl || !publicKeyUrl) {
48
+ throw new Error(`${description} is not signed by the registry - there is nothing to verify.`);
49
+ }
50
+
51
+ const [signature, publicKeyPem] = await Promise.all([
52
+ downloadSignature(registry, signatureUrl),
53
+ downloadPublicKey(registry, publicKeyUrl)
54
+ ]);
55
+
56
+ const packageBytes = await fs.promises.readFile(options.packagePath);
57
+ const publicKey = crypto.createPublicKey({ key: publicKeyPem, format: 'pem' });
58
+ const verified = crypto.verify(null, packageBytes, publicKey, signature);
59
+
60
+ if (!verified) {
61
+ throw new Error(
62
+ `${description} does not match the version published to ${registry.url}. `
63
+ + 'The package may have been tampered with, or did not come from that registry.'
64
+ );
65
+ }
66
+ console.log(`✅ This package is identical to ${description} as published to ${registry.url}.`);
67
+ }
68
+
69
+ /**
70
+ * `registry.getMetadata` always returns the latest version. Follow `allVersions` to the exact
71
+ * version recorded in the package's own manifest when it differs.
72
+ */
73
+ async function resolveVersion(registry: Registry, extension: Extension, version: string): Promise<Extension> {
74
+ if (extension.version === version) {
75
+ return extension;
76
+ }
77
+ const versionUrl = extension.allVersions[version];
78
+ if (!versionUrl) {
79
+ throw new Error(`${extension.namespace}.${extension.name} has no published version '${version}'.`);
80
+ }
81
+ return registry.getJson(new URL(versionUrl));
82
+ }
83
+
84
+ async function downloadSignature(registry: Registry, url: string): Promise<Buffer> {
85
+ const sigzipPath = getTempFilePath('.sigzip');
86
+ try {
87
+ await registry.download(sigzipPath, new URL(url));
88
+ const entries = await readZip(sigzipPath, name => name === SIGNATURE_ENTRY);
89
+ const signature = entries.get(SIGNATURE_ENTRY);
90
+ if (!signature) {
91
+ throw new Error(`The signature archive does not contain a '${SIGNATURE_ENTRY}' entry.`);
92
+ }
93
+ return signature;
94
+ } finally {
95
+ await fs.promises.rm(sigzipPath, { force: true });
96
+ }
97
+ }
98
+
99
+ async function downloadPublicKey(registry: Registry, url: string): Promise<string> {
100
+ const publicKeyPath = getTempFilePath('.pem');
101
+ try {
102
+ await registry.download(publicKeyPath, new URL(url));
103
+ return await fs.promises.readFile(publicKeyPath, 'utf-8');
104
+ } finally {
105
+ await fs.promises.rm(publicKeyPath, { force: true });
106
+ }
107
+ }
package/src/zip.ts CHANGED
@@ -7,20 +7,13 @@
7
7
  *
8
8
  * SPDX-License-Identifier: EPL-2.0
9
9
  ********************************************************************************/
10
+ import * as crypto from 'crypto';
10
11
  import * as yauzl from 'yauzl-promise';
11
- import { Readable } from 'stream';
12
+ import { buffer } from 'stream/consumers';
13
+ import { pipeline } from 'stream/promises';
12
14
  import { Manifest } from './util';
13
15
 
14
- async function bufferStream(stream: Readable): Promise<Buffer> {
15
- return await new Promise((resolve, reject) => {
16
- const buffers: Buffer[] = [];
17
- stream.on('data', buffer => buffers.push(buffer));
18
- stream.once('error', reject);
19
- stream.once('end', () => resolve(Buffer.concat(buffers)));
20
- });
21
- }
22
-
23
- async function readZip(packagePath: string, filter: (name: string) => boolean): Promise<Map<string, Buffer>> {
16
+ export async function readZip(packagePath: string, filter: (name: string) => boolean): Promise<Map<string, Buffer>> {
24
17
  const result = new Map<string, Buffer>();
25
18
  const zipfile = await yauzl.open(packagePath);
26
19
  try {
@@ -28,9 +21,36 @@ async function readZip(packagePath: string, filter: (name: string) => boolean):
28
21
  const name = entry.filename.toLowerCase();
29
22
  if (filter(name)) {
30
23
  const stream = await zipfile.openReadStream(entry);
31
- const buffer = await bufferStream(stream);
32
- result.set(name, buffer);
24
+ result.set(name, await buffer(stream));
25
+ }
26
+ }
27
+ } finally {
28
+ await zipfile.close();
29
+ }
30
+
31
+ return result;
32
+ }
33
+
34
+ /**
35
+ * Computes the SHA256 digest of every non-directory entry of a zip file, keyed by its exact
36
+ * (case-preserving) name - unlike {@link readZip}, which lowercases names for its
37
+ * case-insensitive-filter callers. Used where entry names and digests are compared against another
38
+ * source of truth, such as a signature manifest that records the original names, without also
39
+ * having to hold every entry's full content in memory at once alongside it - each entry's content
40
+ * is streamed straight into a hash and discarded, one entry at a time.
41
+ */
42
+ export async function hashAllZipEntries(packagePath: string): Promise<Map<string, string>> {
43
+ const result = new Map<string, string>();
44
+ const zipfile = await yauzl.open(packagePath);
45
+ try {
46
+ for await (const entry of zipfile) {
47
+ if (entry.filename.endsWith('/')) {
48
+ continue;
33
49
  }
50
+ const stream = await zipfile.openReadStream(entry);
51
+ const hash = crypto.createHash('sha256');
52
+ await pipeline(stream, hash);
53
+ result.set(entry.filename, hash.digest('base64'));
34
54
  }
35
55
  } finally {
36
56
  await zipfile.close();
package/lib/version.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare const LIB_VERSION = "1.1.1";
2
- //# sourceMappingURL=version.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,UAAU,CAAC"}
package/lib/version.js DELETED
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LIB_VERSION = void 0;
4
- exports.LIB_VERSION = "1.1.1";
5
- //# sourceMappingURL=version.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,OAAO,CAAC"}
package/src/version.ts DELETED
@@ -1 +0,0 @@
1
- export const LIB_VERSION = "1.1.1";