@push.rocks/smartlinuxrepo 1.1.1 → 1.2.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 (51) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/alpine/apkindexreader.d.ts +87 -0
  3. package/dist_ts/alpine/apkindexreader.js +193 -0
  4. package/dist_ts/arch/indexreader.d.ts +35 -0
  5. package/dist_ts/arch/indexreader.js +45 -0
  6. package/dist_ts/arch/reader.js +2 -2
  7. package/dist_ts/debian/indexbuilder.js +8 -23
  8. package/dist_ts/debian/indexreader.d.ts +107 -0
  9. package/dist_ts/debian/indexreader.js +274 -0
  10. package/dist_ts/debian/reader.js +6 -2
  11. package/dist_ts/debian/rules.d.ts +18 -0
  12. package/dist_ts/debian/rules.js +81 -2
  13. package/dist_ts/index.d.ts +14 -4
  14. package/dist_ts/index.js +9 -3
  15. package/dist_ts/readers/decompress.d.ts +14 -5
  16. package/dist_ts/readers/decompress.js +401 -26
  17. package/dist_ts/readers/document.d.ts +36 -0
  18. package/dist_ts/readers/document.js +110 -0
  19. package/dist_ts/rpm/repodata.d.ts +3 -2
  20. package/dist_ts/rpm/repodata.js +5 -4
  21. package/dist_ts/rpm/repodatareader.d.ts +173 -0
  22. package/dist_ts/rpm/repodatareader.js +414 -0
  23. package/dist_ts/rpm/xmlreader.d.ts +70 -0
  24. package/dist_ts/rpm/xmlreader.js +576 -0
  25. package/dist_ts/shared/errors.d.ts +12 -4
  26. package/dist_ts/shared/errors.js +1 -1
  27. package/dist_ts/shared/limits.d.ts +9 -2
  28. package/dist_ts/shared/limits.js +5 -2
  29. package/dist_ts/shared/types.d.ts +2 -0
  30. package/dist_ts/signing/verifiers.d.ts +43 -0
  31. package/dist_ts/signing/verifiers.js +81 -2
  32. package/package.json +1 -1
  33. package/readme.md +56 -3
  34. package/ts/00_commitinfo_data.ts +1 -1
  35. package/ts/alpine/apkindexreader.ts +265 -0
  36. package/ts/arch/indexreader.ts +66 -0
  37. package/ts/arch/reader.ts +3 -2
  38. package/ts/debian/indexbuilder.ts +13 -23
  39. package/ts/debian/indexreader.ts +372 -0
  40. package/ts/debian/reader.ts +7 -2
  41. package/ts/debian/rules.ts +83 -1
  42. package/ts/index.ts +40 -2
  43. package/ts/readers/decompress.ts +442 -32
  44. package/ts/readers/document.ts +136 -0
  45. package/ts/rpm/repodata.ts +4 -3
  46. package/ts/rpm/repodatareader.ts +582 -0
  47. package/ts/rpm/xmlreader.ts +680 -0
  48. package/ts/shared/errors.ts +13 -4
  49. package/ts/shared/limits.ts +10 -2
  50. package/ts/shared/types.ts +3 -0
  51. package/ts/signing/verifiers.ts +113 -1
@@ -5,7 +5,9 @@ import type { ILinuxPackageLimits } from './limits.js';
5
5
  * - `unsupported-compression`: a compression the format does not allow.
6
6
  * - `malformed-archive`: broken container structure (ar, tar, gzip, xz, zstd framing or data).
7
7
  * - `malformed-header`: a broken package header (RPM lead and headers).
8
- * - `missing-field` / `invalid-field`: package metadata that is absent or not acceptable.
8
+ * - `missing-field` / `invalid-field`: package metadata that is absent or not acceptable; for the index
9
+ * readers, a unit without its key (`Filename`, `pkgid`, `id`, a `<data>` part, the `APKINDEX` member)
10
+ * or a Release checksum line that fails its grammar.
9
11
  * - `unsupported-package-format`: input that is not the expected package format, or uses a form of it
10
12
  * the codec does not read (the data of a sparse tar entry).
11
13
  * - `truncated`: only a clean early end of input.
@@ -16,14 +18,20 @@ import type { ILinuxPackageLimits } from './limits.js';
16
18
  * - `malformed-signature`: an OpenPGP signature or cleartext-signed message the verifier refuses before
17
19
  * any cryptography: armor, encoding, framing, packet count, version, signature type, a hash outside
18
20
  * SHA-256/384/512, a `Hash:` header that does not name the signature's hash, a missing creation time,
19
- * a missing or wildcard issuer, or an unknown critical subpacket or notation.
21
+ * a missing or wildcard issuer, or an unknown critical subpacket or notation; and an Alpine index
22
+ * whose signature member the Alpine verifier refuses (no `.SIGN.` entry, more than one, a type other
23
+ * than `RSA`, an entry that is not a regular `.SIGN.<type>.<keyName>` file).
20
24
  * - `wrong-key`: the signature's issuer is neither the verifier's primary key nor one of its subkeys, or
21
- * its issuer fingerprint disagrees (`detail.value` carries the issuer in hex).
25
+ * its issuer fingerprint disagrees (`detail.value` carries the issuer in hex); for the Alpine verifier,
26
+ * the `.SIGN.RSA.<keyName>` entry names another key (`detail.value` carries that key name).
22
27
  * - `unusable-key`: the issuing key or subkey cannot sign at the signature's creation time or at the
23
28
  * verification date: expired, revoked, no sign flag, a bad binding or back-signature, created after
24
29
  * the signature, or below the algorithm floor.
25
30
  * - `bad-signature`: the cryptographic check failed, the signature was created after the verification
26
31
  * date, or it has expired at that date.
32
+ * - `malformed-index`: an index document an index reader refuses (1.2.0): line framing, block or
33
+ * stanza structure, XML well-formedness, a DOCTYPE, an unexpected root or child element, an
34
+ * ambiguous duplicate key line or element, or a tar member type an index does not hold.
27
35
  *
28
36
  * New codes arrive in minor releases: a consumer that switches over `code` needs a default branch.
29
37
  *
@@ -31,7 +39,7 @@ import type { ILinuxPackageLimits } from './limits.js';
31
39
  * source or from a caller-supplied signer propagates unchanged. An underlying
32
40
  * error the codec reacts to is kept in the standard `cause`.
33
41
  */
34
- export type TLinuxRepoErrorCode = 'limit-exceeded' | 'unsupported-compression' | 'malformed-archive' | 'malformed-header' | 'missing-field' | 'invalid-field' | 'unsupported-package-format' | 'truncated' | 'digest-mismatch' | 'invalid-input' | 'invalid-key' | 'signing-failed' | 'malformed-signature' | 'wrong-key' | 'unusable-key' | 'bad-signature';
42
+ export type TLinuxRepoErrorCode = 'limit-exceeded' | 'unsupported-compression' | 'malformed-archive' | 'malformed-header' | 'missing-field' | 'invalid-field' | 'unsupported-package-format' | 'truncated' | 'digest-mismatch' | 'invalid-input' | 'invalid-key' | 'signing-failed' | 'malformed-signature' | 'wrong-key' | 'unusable-key' | 'bad-signature' | 'malformed-index';
35
43
  /** Names the field, structure or limit an error is about. */
36
44
  export interface ILinuxRepoErrorDetail {
37
45
  field?: string;
@@ -19,4 +19,4 @@ export function limitExceeded(limitArg, maximumArg, whatArg) {
19
19
  export function truncated(whatArg) {
20
20
  return new LinuxRepoError('truncated', `input ended inside ${whatArg}`, { field: whatArg });
21
21
  }
22
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2hhcmVkL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUEyREEsTUFBTSxPQUFPLGNBQWUsU0FBUSxLQUFLO0lBQ3ZCLElBQUksQ0FBc0I7SUFDMUIsTUFBTSxDQUFrQztJQUV4RCxZQUNFLE9BQTRCLEVBQzVCLFVBQWtCLEVBQ2xCLFNBQVMsR0FBMEIsRUFBRSxFQUNyQyxVQUFnQztRQUVoQyxLQUFLLENBQ0gsVUFBVSxFQUNWLFVBQVUsS0FBSyxTQUFTLElBQUksT0FBTyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQzVGLENBQUM7UUFDRixJQUFJLENBQUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO1FBQzdCLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEdBQUcsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0NBQ0Y7QUFFRCx1REFBdUQ7QUFDdkQsTUFBTSxVQUFVLGFBQWEsQ0FDM0IsUUFBbUMsRUFDbkMsVUFBa0IsRUFDbEIsT0FBZTtJQUVmLE9BQU8sSUFBSSxjQUFjLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxPQUFPLFlBQVksUUFBUSxLQUFLLFVBQVUsR0FBRyxFQUFFO1FBQzVGLEtBQUssRUFBRSxRQUFRO1FBQ2YsS0FBSyxFQUFFLFVBQVU7S0FDbEIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsU0FBUyxDQUFDLE9BQWU7SUFDdkMsT0FBTyxJQUFJLGNBQWMsQ0FBQyxXQUFXLEVBQUUsc0JBQXNCLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDOUYsQ0FBQyJ9
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2hhcmVkL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvRUEsTUFBTSxPQUFPLGNBQWUsU0FBUSxLQUFLO0lBQ3ZCLElBQUksQ0FBc0I7SUFDMUIsTUFBTSxDQUFrQztJQUV4RCxZQUNFLE9BQTRCLEVBQzVCLFVBQWtCLEVBQ2xCLFNBQVMsR0FBMEIsRUFBRSxFQUNyQyxVQUFnQztRQUVoQyxLQUFLLENBQ0gsVUFBVSxFQUNWLFVBQVUsS0FBSyxTQUFTLElBQUksT0FBTyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQzVGLENBQUM7UUFDRixJQUFJLENBQUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO1FBQzdCLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEdBQUcsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0NBQ0Y7QUFFRCx1REFBdUQ7QUFDdkQsTUFBTSxVQUFVLGFBQWEsQ0FDM0IsUUFBbUMsRUFDbkMsVUFBa0IsRUFDbEIsT0FBZTtJQUVmLE9BQU8sSUFBSSxjQUFjLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxPQUFPLFlBQVksUUFBUSxLQUFLLFVBQVUsR0FBRyxFQUFFO1FBQzVGLEtBQUssRUFBRSxRQUFRO1FBQ2YsS0FBSyxFQUFFLFVBQVU7S0FDbEIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsU0FBUyxDQUFDLE9BQWU7SUFDdkMsT0FBTyxJQUFJLGNBQWMsQ0FBQyxXQUFXLEVBQUUsc0JBQXNCLE9BQU8sRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDOUYsQ0FBQyJ9
@@ -17,7 +17,7 @@ export interface ILinuxPackageLimits {
17
17
  maxDecompressedMetadataBytes: number;
18
18
  /** The decompressed Arch payload walked for the file list, in bytes. */
19
19
  maxPayloadBytes: number;
20
- /** Tar or ar entries per archive, and values per multi-valued metadata field. */
20
+ /** Tar or ar entries per archive, Zstandard frames per zstd stream, and values per multi-valued metadata field. */
21
21
  maxEntries: number;
22
22
  /** Total bytes of Arch file names. */
23
23
  maxFileListBytes: number;
@@ -27,6 +27,11 @@ export interface ILinuxPackageLimits {
27
27
  * `maxMetadataBytes`, not here.
28
28
  */
29
29
  maxHeaderBytes: number;
30
+ /**
31
+ * One decoded index document (decompressed output, or the plain input), in
32
+ * bytes. Only the index readers read it (1.2.0).
33
+ */
34
+ maxIndexBytes: number;
30
35
  }
31
36
  /**
32
37
  * The default limits. They accept anything a stock Gitea 28.2.0 stores in
@@ -37,7 +42,9 @@ export interface ILinuxPackageLimits {
37
42
  * - `maxEntries` and `maxFileListBytes` are Gitea's Arch file-list caps
38
43
  * (Alpine's 1024 `.PKGINFO` values fold into `maxEntries`);
39
44
  * - `maxHeaderBytes` covers a full PAX + GNU long name + GNU long link chain at
40
- * Go `archive/tar`'s 1 MiB per special record, and Gitea's 64 KiB line limit.
45
+ * Go `archive/tar`'s 1 MiB per special record, and Gitea's 64 KiB line limit;
46
+ * - `maxIndexBytes` bounds the memory of one index reader call (the decoded
47
+ * document is buffered once); 256 MiB holds a full Debian `main` `Packages`.
41
48
  */
42
49
  export declare const DEFAULT_LINUX_PACKAGE_LIMITS: Readonly<ILinuxPackageLimits>;
43
50
  /**
@@ -11,7 +11,9 @@ const GiB = 1024 * MiB;
11
11
  * - `maxEntries` and `maxFileListBytes` are Gitea's Arch file-list caps
12
12
  * (Alpine's 1024 `.PKGINFO` values fold into `maxEntries`);
13
13
  * - `maxHeaderBytes` covers a full PAX + GNU long name + GNU long link chain at
14
- * Go `archive/tar`'s 1 MiB per special record, and Gitea's 64 KiB line limit.
14
+ * Go `archive/tar`'s 1 MiB per special record, and Gitea's 64 KiB line limit;
15
+ * - `maxIndexBytes` bounds the memory of one index reader call (the decoded
16
+ * document is buffered once); 256 MiB holds a full Debian `main` `Packages`.
15
17
  */
16
18
  export const DEFAULT_LINUX_PACKAGE_LIMITS = Object.freeze({
17
19
  maxPackageBytes: 8 * GiB,
@@ -21,6 +23,7 @@ export const DEFAULT_LINUX_PACKAGE_LIMITS = Object.freeze({
21
23
  maxEntries: 100_000,
22
24
  maxFileListBytes: 16 * MiB,
23
25
  maxHeaderBytes: 4 * MiB,
26
+ maxIndexBytes: 256 * MiB,
24
27
  });
25
28
  const LIMIT_KEYS = Object.keys(DEFAULT_LINUX_PACKAGE_LIMITS);
26
29
  /**
@@ -54,4 +57,4 @@ export function resolveLinuxPackageLimits(overrides) {
54
57
  }
55
58
  return Object.freeze(resolved);
56
59
  }
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGltaXRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2hhcmVkL2xpbWl0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBaUM3QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUM7QUFDakIsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLEdBQUcsQ0FBQztBQUN2QixNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsR0FBRyxDQUFDO0FBRXZCOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBa0MsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN2RixlQUFlLEVBQUUsQ0FBQyxHQUFHLEdBQUc7SUFDeEIsZ0JBQWdCLEVBQUUsRUFBRSxHQUFHLEdBQUc7SUFDMUIsNEJBQTRCLEVBQUUsRUFBRSxHQUFHLEdBQUc7SUFDdEMsZUFBZSxFQUFFLEVBQUUsR0FBRyxHQUFHO0lBQ3pCLFVBQVUsRUFBRSxPQUFPO0lBQ25CLGdCQUFnQixFQUFFLEVBQUUsR0FBRyxHQUFHO0lBQzFCLGNBQWMsRUFBRSxDQUFDLEdBQUcsR0FBRztDQUN4QixDQUFDLENBQUM7QUFFSCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLDRCQUE0QixDQUFxQyxDQUFDO0FBRWpHOzs7R0FHRztBQUNILE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsU0FBd0M7SUFFeEMsSUFBSSxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDNUIsT0FBTyw0QkFBNEIsQ0FBQztJQUN0QyxDQUFDO0lBQ0QsSUFBSSxTQUFTLEtBQUssSUFBSSxJQUFJLE9BQU8sU0FBUyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDcEYsTUFBTSxJQUFJLGNBQWMsQ0FBQyxlQUFlLEVBQUUsMEJBQTBCLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQXdCLEVBQUUsR0FBRyw0QkFBNEIsRUFBRSxDQUFDO0lBQzFFLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ3pDLElBQUksQ0FBRSxVQUF1QixDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxjQUFjLENBQUMsZUFBZSxFQUFFLGtCQUFrQixHQUFHLEdBQUcsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDdkcsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLEdBQWdDLENBQUM7UUFDbEQsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xDLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hCLFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUM1RSxNQUFNLElBQUksY0FBYyxDQUFDLGVBQWUsRUFBRSxTQUFTLFFBQVEsa0NBQWtDLEVBQUU7Z0JBQzdGLEtBQUssRUFBRSxRQUFRO2dCQUNmLEtBQUssRUFBRSxRQUFRO2FBQ2hCLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzdCLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDakMsQ0FBQyJ9
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGltaXRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2hhcmVkL2xpbWl0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBc0M3QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUM7QUFDakIsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLEdBQUcsQ0FBQztBQUN2QixNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsR0FBRyxDQUFDO0FBRXZCOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFrQyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3ZGLGVBQWUsRUFBRSxDQUFDLEdBQUcsR0FBRztJQUN4QixnQkFBZ0IsRUFBRSxFQUFFLEdBQUcsR0FBRztJQUMxQiw0QkFBNEIsRUFBRSxFQUFFLEdBQUcsR0FBRztJQUN0QyxlQUFlLEVBQUUsRUFBRSxHQUFHLEdBQUc7SUFDekIsVUFBVSxFQUFFLE9BQU87SUFDbkIsZ0JBQWdCLEVBQUUsRUFBRSxHQUFHLEdBQUc7SUFDMUIsY0FBYyxFQUFFLENBQUMsR0FBRyxHQUFHO0lBQ3ZCLGFBQWEsRUFBRSxHQUFHLEdBQUcsR0FBRztDQUN6QixDQUFDLENBQUM7QUFFSCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLDRCQUE0QixDQUFxQyxDQUFDO0FBRWpHOzs7R0FHRztBQUNILE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsU0FBd0M7SUFFeEMsSUFBSSxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDNUIsT0FBTyw0QkFBNEIsQ0FBQztJQUN0QyxDQUFDO0lBQ0QsSUFBSSxTQUFTLEtBQUssSUFBSSxJQUFJLE9BQU8sU0FBUyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDcEYsTUFBTSxJQUFJLGNBQWMsQ0FBQyxlQUFlLEVBQUUsMEJBQTBCLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQXdCLEVBQUUsR0FBRyw0QkFBNEIsRUFBRSxDQUFDO0lBQzFFLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ3pDLElBQUksQ0FBRSxVQUF1QixDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxjQUFjLENBQUMsZUFBZSxFQUFFLGtCQUFrQixHQUFHLEdBQUcsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDdkcsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLEdBQWdDLENBQUM7UUFDbEQsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xDLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hCLFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUM1RSxNQUFNLElBQUksY0FBYyxDQUFDLGVBQWUsRUFBRSxTQUFTLFFBQVEsa0NBQWtDLEVBQUU7Z0JBQzdGLEtBQUssRUFBRSxRQUFRO2dCQUNmLEtBQUssRUFBRSxRQUFRO2FBQ2hCLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQzdCLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDakMsQ0FBQyJ9
@@ -211,3 +211,5 @@ export interface ILinuxIndexFile {
211
211
  /** Other paths serving the same bytes (Debian `by-hash/<ALGO>/<hex>` for every listed hash). */
212
212
  aliases: string[];
213
213
  }
214
+ /** The stream compressions the readers decode; the caller names it from the file name. */
215
+ export type TLinuxCompression = 'none' | 'gzip' | 'xz' | 'zstd';
@@ -1,3 +1,4 @@
1
+ import { type ILinuxPackageLimits } from '../shared/limits.js';
1
2
  /** The hash algorithms the verifier accepts. */
2
3
  export type TOpenPgpHashAlgorithm = 'sha256' | 'sha384' | 'sha512';
3
4
  /** A signature that verified. */
@@ -75,3 +76,45 @@ export interface IOpenPgpVerifier {
75
76
  export declare function createOpenPgpVerifier(inputArg: {
76
77
  publicKeyArmored: string;
77
78
  }): Promise<IOpenPgpVerifier>;
79
+ /** An Alpine index signature that verified. */
80
+ export interface IAlpineSignatureVerification {
81
+ /** The key name of the `.SIGN.RSA.<keyName>` entry: the verifier's. */
82
+ readonly keyName: string;
83
+ readonly hashAlgorithm: 'sha1';
84
+ }
85
+ /**
86
+ * Verifies Alpine index signatures against one RSA public key. Fails closed
87
+ * with a `LinuxRepoError` and never returns a verdict of failure:
88
+ * `malformed-signature`, `wrong-key` or `bad-signature` (bad arguments are
89
+ * `invalid-input`; the index's own framing keeps its reader codes).
90
+ */
91
+ export interface IAlpineVerifier {
92
+ /** The key name apk finds the public key under (`/etc/apk/keys/<keyName>`). */
93
+ readonly keyName: string;
94
+ /**
95
+ * Verifies the one `.SIGN.RSA.<keyName>` entry of an `APKINDEX.tar.gz` over
96
+ * its signed bytes (everything after the signature member): RSASSA-PKCS1-v1_5
97
+ * over SHA-1, as apk-tools 2 and Gitea sign. The split is
98
+ * `readAlpineIndex`'s; no signature member, more than one `.SIGN.` entry or
99
+ * a type other than `RSA` is `malformed-signature`, an entry naming another
100
+ * key `wrong-key` (`detail.value` the entry's key name), and a signature
101
+ * that does not verify `bad-signature`. The format carries no time.
102
+ */
103
+ verifyIndexSignature(inputArg: {
104
+ index: Uint8Array;
105
+ limits?: Partial<ILinuxPackageLimits>;
106
+ }): Promise<IAlpineSignatureVerification>;
107
+ }
108
+ /**
109
+ * Builds an Alpine verifier from one PKIX `PUBLIC KEY` PEM block, the form
110
+ * Gitea serves (`GET /alpine/key`, `util.GenerateKeyPair`) and Alpine installs
111
+ * in `/etc/apk/keys`, and the key name apk finds it under. The PEM must be
112
+ * exactly one block with nothing around it but one final LF, and an RSA key
113
+ * of at least 2047 bits (the OpenPGP verifier's floor); anything else is
114
+ * `invalid-key` (`publicKeyPem`). A `keyName` that is empty or holds `/` or a
115
+ * control character is `invalid-input`.
116
+ */
117
+ export declare function createAlpineVerifier(inputArg: {
118
+ publicKeyPem: string;
119
+ keyName: string;
120
+ }): IAlpineVerifier;
@@ -1,6 +1,8 @@
1
1
  import * as plugins from '../plugins.js';
2
+ import { splitAlpineIndexSignature } from '../alpine/apkindexreader.js';
2
3
  import { LinuxRepoError } from '../shared/errors.js';
3
- import { assertBytes, assertString, assertTimestamp } from '../shared/validation.js';
4
+ import { resolveLinuxPackageLimits } from '../shared/limits.js';
5
+ import { assertBytes, assertSegmentName, assertString, assertTimestamp } from '../shared/validation.js';
4
6
  import { dearmor, decodeArmorBytes, readPacketTags, splitCleartextSignedMessage, } from './openpgpframing.js';
5
7
  const HASH_ALGORITHMS = new Map([
6
8
  [plugins.openpgp.enums.hash.sha256, 'sha256'],
@@ -260,4 +262,81 @@ async function verifySignature(inputArg) {
260
262
  hashAlgorithm,
261
263
  };
262
264
  }
263
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyaWZpZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2lnbmluZy92ZXJpZmllcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JGLE9BQU8sRUFDTCxPQUFPLEVBQ1AsZ0JBQWdCLEVBQ2hCLGNBQWMsRUFDZCwyQkFBMkIsR0FFNUIsTUFBTSxxQkFBcUIsQ0FBQztBQWdFN0IsTUFBTSxlQUFlLEdBQStDLElBQUksR0FBRyxDQUFDO0lBQzFFLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUM7SUFDN0MsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQztJQUM3QyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDO0NBQzlDLENBQUMsQ0FBQztBQUVILDhHQUE4RztBQUM5RyxNQUFNLHdCQUF3QixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRXZEOzs7O0dBSUc7QUFDSCxNQUFNLGFBQWEsR0FBMkI7SUFDNUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU07SUFDekIsd0JBQXdCLEVBQUUsS0FBSztJQUMvQixzQkFBc0IsRUFBRSxLQUFLO0lBQzdCLHVCQUF1QixFQUFFLEtBQUs7SUFDOUIsd0JBQXdCLEVBQUUsRUFBRTtJQUM1QixvQkFBb0IsRUFBRSxLQUFLO0lBQzNCLDRDQUE0QyxF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
265
+ /** The OpenPGP verifier's RSA floor (`VERIFY_CONFIG.minRSABits`), for the Alpine key too. */
266
+ const ALPINE_MIN_RSA_BITS = 2047;
267
+ const ALPINE_PUBLIC_KEY_PEM = /^-----BEGIN PUBLIC KEY-----\n(?:[A-Za-z0-9+/=]+\n)+-----END PUBLIC KEY-----\n?$/;
268
+ /**
269
+ * Builds an Alpine verifier from one PKIX `PUBLIC KEY` PEM block, the form
270
+ * Gitea serves (`GET /alpine/key`, `util.GenerateKeyPair`) and Alpine installs
271
+ * in `/etc/apk/keys`, and the key name apk finds it under. The PEM must be
272
+ * exactly one block with nothing around it but one final LF, and an RSA key
273
+ * of at least 2047 bits (the OpenPGP verifier's floor); anything else is
274
+ * `invalid-key` (`publicKeyPem`). A `keyName` that is empty or holds `/` or a
275
+ * control character is `invalid-input`.
276
+ */
277
+ export function createAlpineVerifier(inputArg) {
278
+ if (inputArg === null || typeof inputArg !== 'object') {
279
+ throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
280
+ }
281
+ assertString(inputArg.publicKeyPem, 'publicKeyPem');
282
+ assertSegmentName(inputArg.keyName, 'keyName');
283
+ if (!ALPINE_PUBLIC_KEY_PEM.test(inputArg.publicKeyPem)) {
284
+ throw new LinuxRepoError('invalid-key', 'the Alpine public key must be exactly one PKIX "PUBLIC KEY" PEM block', {
285
+ field: 'publicKeyPem',
286
+ });
287
+ }
288
+ let key;
289
+ try {
290
+ key = plugins.crypto.createPublicKey({ key: inputArg.publicKeyPem, format: 'pem' });
291
+ }
292
+ catch (error) {
293
+ throw new LinuxRepoError('invalid-key', 'the Alpine public key cannot be read', { field: 'publicKeyPem' }, {
294
+ cause: error,
295
+ });
296
+ }
297
+ const modulusLength = key.asymmetricKeyDetails?.modulusLength ?? 0;
298
+ if (key.asymmetricKeyType !== 'rsa' || modulusLength < ALPINE_MIN_RSA_BITS) {
299
+ throw new LinuxRepoError('invalid-key', `the Alpine public key must be an RSA key of at least ${ALPINE_MIN_RSA_BITS} bits`, {
300
+ field: 'publicKeyPem',
301
+ });
302
+ }
303
+ const keyName = inputArg.keyName;
304
+ return {
305
+ keyName,
306
+ verifyIndexSignature: async (input) => {
307
+ assertInputObject(input);
308
+ assertBytes(input.index, 'index');
309
+ const limits = resolveLinuxPackageLimits(input.limits);
310
+ const split = await splitAlpineIndexSignature(input.index, limits);
311
+ const malformed = (messageArg) => new LinuxRepoError('malformed-signature', messageArg, { field: 'index' });
312
+ if (split.signatures.length === 0) {
313
+ throw malformed('the index is not signed');
314
+ }
315
+ if (split.signatures.length > 1) {
316
+ throw malformed(`the index holds ${split.signatures.length} .SIGN. entries, expected one`);
317
+ }
318
+ const entry = split.signatures[0];
319
+ if (entry.type !== 'RSA') {
320
+ throw malformed(`the index signature type is ${JSON.stringify(entry.type)}, expected "RSA"`);
321
+ }
322
+ if (entry.keyName !== keyName) {
323
+ throw new LinuxRepoError('wrong-key', 'the index was signed under another key name', {
324
+ field: 'index',
325
+ value: entry.keyName,
326
+ });
327
+ }
328
+ let verified;
329
+ try {
330
+ verified = plugins.crypto.verify('sha1', input.index.subarray(split.signedOffset), { key, padding: plugins.crypto.constants.RSA_PKCS1_PADDING }, entry.signature);
331
+ }
332
+ catch (error) {
333
+ throw new LinuxRepoError('bad-signature', 'the index signature does not verify', { field: 'index' }, { cause: error });
334
+ }
335
+ if (!verified) {
336
+ throw new LinuxRepoError('bad-signature', 'the index signature does not verify', { field: 'index' });
337
+ }
338
+ return { keyName, hashAlgorithm: 'sha1' };
339
+ },
340
+ };
341
+ }
342
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyaWZpZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc2lnbmluZy92ZXJpZmllcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFBRSx5QkFBeUIsRUFBNEIsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRixPQUFPLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RyxPQUFPLEVBQ0wsT0FBTyxFQUNQLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsMkJBQTJCLEdBRTVCLE1BQU0scUJBQXFCLENBQUM7QUFnRTdCLE1BQU0sZUFBZSxHQUErQyxJQUFJLEdBQUcsQ0FBQztJQUMxRSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDO0lBQzdDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUM7SUFDN0MsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQztDQUM5QyxDQUFDLENBQUM7QUFFSCw4R0FBOEc7QUFDOUcsTUFBTSx3QkFBd0IsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUV2RDs7OztHQUlHO0FBQ0gsTUFBTSxhQUFhLEdBQTJCO0lBQzVDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNO0lBQ3pCLHdCQUF3QixFQUFFLEtBQUs7SUFD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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartlinuxrepo",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "private": false,
5
5
  "description": "A pure codec for Linux package repositories (Alpine apk, Debian apt, RPM dnf, Arch pacman): read packages into records, build index file sets and sign them.",
6
6
  "main": "dist_ts/index.js",
package/readme.md CHANGED
@@ -16,7 +16,7 @@ Node.js `^24.20.0 || >=26.6.0`: the releases whose `node:zlib` reports a truncat
16
16
 
17
17
  ## Status
18
18
 
19
- All four formats read, index and sign: `readAlpinePackage`, `readDebianPackage`, `readRpmPackage` and `readArchPackage` read packages into records; `buildAlpineIndex`, `buildDebianIndex`, `buildRpmIndex` and `buildArchIndex` build signed index file sets; `signRpmPackage` and `signArchPackage` sign packages at upload. Each format is checked against Gitea 28.2.0's own output and installed from with apk, apt, dnf and pacman. `createOpenPgpVerifier` verifies OpenPGP detached and cleartext signatures (see Verification). The built-in OpenPGP signer does not stream: openpgp.js 6.3.2 holds a detached-signed document in memory (see Signing).
19
+ All four formats read, index and sign: `readAlpinePackage`, `readDebianPackage`, `readRpmPackage` and `readArchPackage` read packages into records; `buildAlpineIndex`, `buildDebianIndex`, `buildRpmIndex` and `buildArchIndex` build signed index file sets; `signRpmPackage` and `signArchPackage` sign packages at upload. Each format is checked against Gitea 28.2.0's own output and installed from with apk, apt, dnf and pacman. `createOpenPgpVerifier` verifies OpenPGP detached and cleartext signatures (see Verification). The index readers read served index documents back into units, and `createAlpineVerifier` verifies `APKINDEX.tar.gz` signatures (see Index readers). The built-in OpenPGP signer does not stream: openpgp.js 6.3.2 holds a detached-signed document in memory (see Signing).
20
20
 
21
21
  ## Records
22
22
 
@@ -32,11 +32,14 @@ Readers take `Partial<ILinuxPackageLimits>` per call over `DEFAULT_LINUX_PACKAGE
32
32
  | `maxMetadataBytes` | 64 MiB | one buffered metadata unit (apk or deb control member, RPM headers) |
33
33
  | `maxDecompressedMetadataBytes` | 32 MiB | a decompressed control tar or `.PKGINFO` |
34
34
  | `maxPayloadBytes` | 16 GiB | the decompressed Arch payload walked for the file list |
35
- | `maxEntries` | 100,000 | archive entries, values per multi-valued field |
35
+ | `maxEntries` | 100,000 | archive entries, Zstandard frames per zstd stream, values per multi-valued field |
36
36
  | `maxFileListBytes` | 16 MiB | total Arch file-name bytes |
37
37
  | `maxHeaderBytes` | 4 MiB | one tar header chain or metadata line |
38
+ | `maxIndexBytes` | 256 MiB | one decoded index document (index readers only) |
38
39
 
39
- Every failure is a `LinuxRepoError` with a stable `code` (`limit-exceeded`, `unsupported-compression`, `malformed-archive`, `malformed-header`, `missing-field`, `invalid-field`, `unsupported-package-format`, `truncated`, `digest-mismatch`, `invalid-input`, `invalid-key`, `signing-failed`, and from the verifier `malformed-signature`, `wrong-key`, `unusable-key`, `bad-signature`) and a `detail` naming the field or limit. Errors from your own source or signer, and failures inside node:crypto or openpgp.js during key generation, are passed through unchanged. New codes arrive in minor releases (1.1.0 added the four verifier codes), each raised only by a new function: a `switch` over `code` needs a default branch.
40
+ Every failure is a `LinuxRepoError` with a stable `code` (`limit-exceeded`, `unsupported-compression`, `malformed-archive`, `malformed-header`, `missing-field`, `invalid-field`, `unsupported-package-format`, `truncated`, `digest-mismatch`, `invalid-input`, `invalid-key`, `signing-failed`, from the verifiers `malformed-signature`, `wrong-key`, `unusable-key`, `bad-signature`, and from the index readers `malformed-index`) and a `detail` naming the field or limit. Errors from your own source or signer, and failures inside node:crypto or openpgp.js during key generation, are passed through unchanged. New codes arrive in minor releases (1.1.0 added the four verifier codes, 1.2.0 `malformed-index`), each raised only by a new function: a `switch` over `code` needs a default branch.
41
+
42
+ Compressed streams (a deb control member, an Arch package) are read to their end: concatenated gzip members and zstd frames are decoded, zstd skippable frames are skipped, and any other bytes after the last gzip member or zstd frame are `malformed-archive`.
40
43
 
41
44
  ## Signing
42
45
 
@@ -98,6 +101,56 @@ The verdicts match gpgv as apt reads it (`EXPKEYSIG` and `REVKEYSIG` are refusal
98
101
 
99
102
  Every builder returns the complete file set for its input as `ILinuxIndexFile[]` (`path`, `bytes`, `sha256`, `mediaType`, `stage`, `aliases`); a previously written file that is not in the set is stale. Write every `content` file before any `pointer` file: the pointer files are the signed documents that name the content files.
100
103
 
104
+ ## Index readers
105
+
106
+ The index readers read served index documents back into units, for comparing two producers' indexes (the codec's and Gitea's, say) as multisets of units. A unit is its key, its exact bytes as served (never a re-rendering) and a small lexical view; the parts outside the units come back as raw bytes too.
107
+
108
+ ```ts
109
+ import {
110
+ createAlpineVerifier,
111
+ readAlpineIndex,
112
+ readArchIndex,
113
+ readDebianPackagesIndex,
114
+ readDebianRelease,
115
+ readRpmRepodata,
116
+ readRpmRepomd,
117
+ readRpmUpdateInfo,
118
+ stripDebianIndexOwnedFields,
119
+ } from '@push.rocks/smartlinuxrepo';
120
+
121
+ const packages = await readDebianPackagesIndex({ bytes: packagesXz, compression: 'xz' });
122
+ for (const stanza of packages.stanzas) {
123
+ stanza.filename; // the key: the last Filename
124
+ stanza.bytes; // the stanza's exact bytes
125
+ stripDebianIndexOwnedFields(stanza.bytes); // without Filename, Size, MD5sum, SHA1, SHA256, SHA512
126
+ }
127
+ const release = await readDebianRelease({ bytes: releaseBytes }); // fields in order, files.{md5Sum,sha1,sha256,sha512}
128
+ const primary = await readRpmRepodata({ bytes: primaryGz, compression: 'gzip', document: 'primary' }); // packages by pkgid
129
+ const apkindex = await readAlpineIndex({ bytes: apkindexTarGz }); // signatures, signedBytes, members, blocks
130
+ await createAlpineVerifier({ publicKeyPem, keyName }).verifyIndexSignature({ index: apkindexTarGz });
131
+ const db = await readArchIndex({ bytes: packagesDb, compression: 'gzip' }); // desc and files members by name
132
+ ```
133
+
134
+ | Reader | Document | Units and key | Also returned |
135
+ | --- | --- | --- | --- |
136
+ | `readDebianPackagesIndex` | `Packages`, `.gz`, `.xz` | stanzas; the last `Filename` | `decoded`; `package`, `version`, `architecture` |
137
+ | `readDebianRelease` | `Release` | fields in order | `files.md5Sum`, `sha1`, `sha256`, `sha512` as `{ path, size, digest }` |
138
+ | `readAlpineIndex` | `APKINDEX.tar.gz` | `APKINDEX` blocks; `P:`, `V:`, `A:` | the `.SIGN.*` entries, the signed bytes, the tar members |
139
+ | `readRpmRepodata` | `primary`, `filelists`, `other` | `<package>`; `pkgid` | `decoded`, the XML frame, name, arch, epoch/version/release, `<size>`, files |
140
+ | `readRpmUpdateInfo` | `updateinfo` | `<update>`; `<id>` | `decoded`, the XML frame, the package list |
141
+ | `readRpmRepomd` | `repomd.xml` | `<data>`; `type` | the XML frame, other root elements (`<revision>`, `<tags>`) raw |
142
+ | `readArchIndex` | `packages.db` | tar members; name | `decoded` |
143
+
144
+ - Every reader takes `{ bytes: Uint8Array, ..., limits?: Partial<ILinuxPackageLimits> }` and returns a `Promise`. The compression (`'none' | 'gzip' | 'xz' | 'zstd'`, `TLinuxCompression`) and the RPM `document` are named by the caller from the file name; nothing is sniffed. A stream with bytes after its last gzip member or zstd frame is `malformed-archive`.
145
+ - A reader fails the whole document with a `LinuxRepoError` and never returns a partial result. Every unit is returned in document order, duplicates included (two stanzas with one `Filename`, two packages with one `pkgid`); nothing is merged.
146
+ - Returned units are views into one buffer the reader allocated (`decoded`); `offset` indexes into it. `readAlpineIndex` has no `decoded`: its units are views into the `APKINDEX` member, and its `signedBytes` and signature bytes are its own copies. No result aliases your input.
147
+ - Bounds: the decoded document by `maxIndexBytes`, units (and values per parsed list, open XML elements, Zstandard frames of a zstd document) by `maxEntries`, one unit by `maxMetadataBytes`, one line or XML start tag by `maxHeaderBytes`.
148
+ - `Packages` and `Release` lines end in LF, the last one too; a line holding only spaces or tabs is `malformed-index`. A `Release` holds one stanza: no empty line, checksum lines of a digest, a size and a path separated by spaces or tabs (`invalid-field` otherwise). To read an `InRelease`, verify it with `createOpenPgpVerifier().verifyCleartextMessage` and pass its `signedText` to `readDebianRelease`, adding a final LF when it lacks one.
149
+ - RPM documents are read by a strict XML scanner: UTF-8 only, no DOCTYPE (so no entities), well-formed, the root the `document` names, only whitespace between units (not returned). The frame (`prolog`, `rootStartTag`, `rootAttributes`, `namespace`, `rootEndTag`, `trailer`) is returned as written; for Gitea's and the codec's documents the frame and the units rebuild `decoded`. `isRpmPrimaryPath` is createrepo_c's `cr_is_primary`, the rule the codec adds to Gitea's primary file list.
150
+ - `readAlpineIndex` splits the index as apk does: the first gzip member is the signature member when its tar's first entry is named `.SIGN.*`. `createAlpineVerifier({ publicKeyPem, keyName })` takes one PKIX `PUBLIC KEY` PEM (what Gitea serves at `/alpine/key` and Alpine installs in `/etc/apk/keys`) of an RSA key of at least 2047 bits and the key name apk finds it under, and verifies RSA PKCS#1 v1.5 over SHA-1 of the signed bytes. It fails closed: `malformed-signature` (unsigned, several `.SIGN.` entries, a type other than `RSA`), `wrong-key` (another key name, `detail.value`), `bad-signature`.
151
+ - `readArchIndex` returns regular files and skips directory entries (pacman's `repo-add` writes them); `desc` and `files` are not parsed. `compareArchVersions` is pacman's `vercmp`.
152
+ - `malformed-index` is an index document a reader refuses: line framing, block or stanza structure, XML well-formedness, an unexpected root or child element, an ambiguous duplicate key line or element (`P:` twice, two `<id>`), or a tar entry type an index does not hold. A unit without its key is `missing-field`.
153
+
101
154
  ## Alpine
102
155
 
103
156
  ```ts
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartlinuxrepo',
6
- version: '1.1.1',
6
+ version: '1.2.0',
7
7
  description: 'A pure codec for Linux package repositories (Alpine apk, Debian apt, RPM dnf, Arch pacman): read packages into records, build index file sets and sign them.'
8
8
  }