@push.rocks/smartlinuxrepo 0.0.0-stage → 1.0.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 (131) hide show
  1. package/.smartconfig.json +65 -0
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/alpine/apkindex.d.ts +39 -0
  5. package/dist_ts/alpine/apkindex.js +211 -0
  6. package/dist_ts/alpine/pkginfo.d.ts +45 -0
  7. package/dist_ts/alpine/pkginfo.js +159 -0
  8. package/dist_ts/alpine/reader.d.ts +20 -0
  9. package/dist_ts/alpine/reader.js +89 -0
  10. package/dist_ts/arch/builder.d.ts +41 -0
  11. package/dist_ts/arch/builder.js +234 -0
  12. package/dist_ts/arch/reader.d.ts +16 -0
  13. package/dist_ts/arch/reader.js +271 -0
  14. package/dist_ts/arch/signer.d.ts +21 -0
  15. package/dist_ts/arch/signer.js +66 -0
  16. package/dist_ts/arch/vercmp.d.ts +12 -0
  17. package/dist_ts/arch/vercmp.js +170 -0
  18. package/dist_ts/debian/control.d.ts +22 -0
  19. package/dist_ts/debian/control.js +137 -0
  20. package/dist_ts/debian/gostring.d.ts +26 -0
  21. package/dist_ts/debian/gostring.js +145 -0
  22. package/dist_ts/debian/indexbuilder.d.ts +47 -0
  23. package/dist_ts/debian/indexbuilder.js +299 -0
  24. package/dist_ts/debian/mailaddress.d.ts +12 -0
  25. package/dist_ts/debian/mailaddress.js +736 -0
  26. package/dist_ts/debian/reader.d.ts +30 -0
  27. package/dist_ts/debian/reader.js +110 -0
  28. package/dist_ts/index.d.ts +23 -0
  29. package/dist_ts/index.js +18 -0
  30. package/dist_ts/plugins.d.ts +8 -0
  31. package/dist_ts/plugins.js +11 -0
  32. package/dist_ts/readers/ar.d.ts +31 -0
  33. package/dist_ts/readers/ar.js +87 -0
  34. package/dist_ts/readers/bytes.d.ts +58 -0
  35. package/dist_ts/readers/bytes.js +147 -0
  36. package/dist_ts/readers/bytesource.d.ts +40 -0
  37. package/dist_ts/readers/bytesource.js +154 -0
  38. package/dist_ts/readers/decompress.d.ts +43 -0
  39. package/dist_ts/readers/decompress.js +269 -0
  40. package/dist_ts/readers/gzipmember.d.ts +32 -0
  41. package/dist_ts/readers/gzipmember.js +176 -0
  42. package/dist_ts/readers/tar.d.ts +85 -0
  43. package/dist_ts/readers/tar.js +731 -0
  44. package/dist_ts/readers/text.d.ts +16 -0
  45. package/dist_ts/readers/text.js +96 -0
  46. package/dist_ts/rpm/builder.d.ts +28 -0
  47. package/dist_ts/rpm/builder.js +208 -0
  48. package/dist_ts/rpm/header.d.ts +138 -0
  49. package/dist_ts/rpm/header.js +546 -0
  50. package/dist_ts/rpm/reader.d.ts +20 -0
  51. package/dist_ts/rpm/reader.js +306 -0
  52. package/dist_ts/rpm/repoconfig.d.ts +15 -0
  53. package/dist_ts/rpm/repoconfig.js +38 -0
  54. package/dist_ts/rpm/repodata.d.ts +44 -0
  55. package/dist_ts/rpm/repodata.js +148 -0
  56. package/dist_ts/rpm/sign.d.ts +30 -0
  57. package/dist_ts/rpm/sign.js +183 -0
  58. package/dist_ts/rpm/updates.d.ts +38 -0
  59. package/dist_ts/rpm/updates.js +265 -0
  60. package/dist_ts/rpm/xml.d.ts +18 -0
  61. package/dist_ts/rpm/xml.js +90 -0
  62. package/dist_ts/shared/architecture.d.ts +8 -0
  63. package/dist_ts/shared/architecture.js +17 -0
  64. package/dist_ts/shared/errors.d.ts +38 -0
  65. package/dist_ts/shared/errors.js +22 -0
  66. package/dist_ts/shared/gopath.d.ts +13 -0
  67. package/dist_ts/shared/gopath.js +53 -0
  68. package/dist_ts/shared/gostrings.d.ts +14 -0
  69. package/dist_ts/shared/gostrings.js +29 -0
  70. package/dist_ts/shared/limits.d.ts +47 -0
  71. package/dist_ts/shared/limits.js +57 -0
  72. package/dist_ts/shared/types.d.ts +213 -0
  73. package/dist_ts/shared/types.js +13 -0
  74. package/dist_ts/shared/url.d.ts +18 -0
  75. package/dist_ts/shared/url.js +371 -0
  76. package/dist_ts/shared/validation.d.ts +21 -0
  77. package/dist_ts/shared/validation.js +58 -0
  78. package/dist_ts/signing/keys.d.ts +36 -0
  79. package/dist_ts/signing/keys.js +89 -0
  80. package/dist_ts/signing/openpgpframing.d.ts +33 -0
  81. package/dist_ts/signing/openpgpframing.js +93 -0
  82. package/dist_ts/signing/signers.d.ts +63 -0
  83. package/dist_ts/signing/signers.js +248 -0
  84. package/dist_ts/writers/gotar.d.ts +43 -0
  85. package/dist_ts/writers/gotar.js +218 -0
  86. package/license.md +19 -0
  87. package/package.json +56 -3
  88. package/readme.md +176 -0
  89. package/ts/00_commitinfo_data.ts +8 -0
  90. package/ts/alpine/apkindex.ts +241 -0
  91. package/ts/alpine/pkginfo.ts +183 -0
  92. package/ts/alpine/reader.ts +96 -0
  93. package/ts/arch/builder.ts +283 -0
  94. package/ts/arch/reader.ts +307 -0
  95. package/ts/arch/signer.ts +70 -0
  96. package/ts/arch/vercmp.ts +188 -0
  97. package/ts/debian/control.ts +150 -0
  98. package/ts/debian/gostring.ts +150 -0
  99. package/ts/debian/indexbuilder.ts +355 -0
  100. package/ts/debian/mailaddress.ts +754 -0
  101. package/ts/debian/reader.ts +126 -0
  102. package/ts/index.ts +46 -0
  103. package/ts/plugins.ts +13 -0
  104. package/ts/readers/ar.ts +102 -0
  105. package/ts/readers/bytes.ts +182 -0
  106. package/ts/readers/bytesource.ts +164 -0
  107. package/ts/readers/decompress.ts +332 -0
  108. package/ts/readers/gzipmember.ts +209 -0
  109. package/ts/readers/tar.ts +835 -0
  110. package/ts/readers/text.ts +91 -0
  111. package/ts/rpm/builder.ts +253 -0
  112. package/ts/rpm/header.ts +628 -0
  113. package/ts/rpm/reader.ts +317 -0
  114. package/ts/rpm/repoconfig.ts +45 -0
  115. package/ts/rpm/repodata.ts +219 -0
  116. package/ts/rpm/sign.ts +200 -0
  117. package/ts/rpm/updates.ts +314 -0
  118. package/ts/rpm/xml.ts +101 -0
  119. package/ts/shared/architecture.ts +16 -0
  120. package/ts/shared/errors.ts +78 -0
  121. package/ts/shared/gopath.ts +54 -0
  122. package/ts/shared/gostrings.ts +31 -0
  123. package/ts/shared/limits.ts +93 -0
  124. package/ts/shared/types.ts +251 -0
  125. package/ts/shared/url.ts +387 -0
  126. package/ts/shared/validation.ts +71 -0
  127. package/ts/signing/keys.ts +110 -0
  128. package/ts/signing/openpgpframing.ts +115 -0
  129. package/ts/signing/signers.ts +315 -0
  130. package/ts/writers/gotar.ts +256 -0
  131. package/README.md +0 -3
@@ -0,0 +1,65 @@
1
+ {
2
+ "@git.zone/cli": {
3
+ "schemaVersion": 2,
4
+ "projectType": "npm",
5
+ "module": {
6
+ "githost": "code.foss.global",
7
+ "gitscope": "push.rocks",
8
+ "gitrepo": "smartlinuxrepo",
9
+ "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.",
10
+ "npmPackagename": "@push.rocks/smartlinuxrepo",
11
+ "license": "MIT",
12
+ "projectDomain": "push.rocks",
13
+ "keywords": [
14
+ "linux",
15
+ "package repository",
16
+ "alpine",
17
+ "apk",
18
+ "debian",
19
+ "apt",
20
+ "rpm",
21
+ "dnf",
22
+ "arch",
23
+ "pacman",
24
+ "openpgp",
25
+ "codec"
26
+ ]
27
+ },
28
+ "release": {
29
+ "confirmation": "prompt",
30
+ "versionFloor": "1.0.0",
31
+ "preflight": {
32
+ "requireCleanTree": true,
33
+ "test": false,
34
+ "build": true
35
+ },
36
+ "targets": {
37
+ "git": {
38
+ "enabled": true,
39
+ "remote": "origin",
40
+ "pushBranch": true,
41
+ "pushTags": true
42
+ },
43
+ "npm": {
44
+ "enabled": true,
45
+ "registries": [
46
+ "https://verdaccio.lossless.digital",
47
+ "https://registry.npmjs.org"
48
+ ],
49
+ "accessLevel": "public",
50
+ "alreadyPublished": "success"
51
+ },
52
+ "docker": {
53
+ "enabled": false,
54
+ "engine": "tsdocker",
55
+ "patterns": []
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "@git.zone/tsrepo": {
61
+ "docs": {
62
+ "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license.md) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * autocreated commitinfo by @push.rocks/commitinfo
3
+ */
4
+ export declare const commitinfo: {
5
+ name: string;
6
+ version: string;
7
+ description: string;
8
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * autocreated commitinfo by @push.rocks/commitinfo
3
+ */
4
+ export const commitinfo = {
5
+ name: '@push.rocks/smartlinuxrepo',
6
+ version: '1.0.0',
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
+ };
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSw0QkFBNEI7SUFDbEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhKQUE4SjtDQUM1SyxDQUFBIn0=
@@ -0,0 +1,39 @@
1
+ import type { IAlpinePackageRecord, ILinuxIndexFile } from '../shared/types.js';
2
+ import type { IAlpineSigner } from '../signing/signers.js';
3
+ /**
4
+ * Builds the `APKINDEX.tar.gz` set of one Alpine repository (one branch and
5
+ * repository) as Gitea 28.2.0 does (`services/packages/alpine/repository.go:150-351`):
6
+ * one index per architecture the entries name, at
7
+ * `{branch}/{repository}/{architecture}/APKINDEX.tar.gz`. Every index other
8
+ * than `noarch` also lists the `noarch` packages, and every block's `A:` is the
9
+ * index's architecture.
10
+ *
11
+ * Each archive is a signature gzip member (a tar entry
12
+ * `.SIGN.RSA.<signer.keyName>` holding RSA PKCS#1 v1.5 over SHA-1 of the
13
+ * unsigned stream, without an end-of-archive marker) followed by the unsigned
14
+ * gzip member (a tar entry `APKINDEX`, mode 0600, with the marker). Tar headers
15
+ * are byte-for-byte what Go `archive/tar` writes for Gitea (`writeGoTar`); the
16
+ * signature entry is padded to its 512-byte block (a difference from Gitea),
17
+ * which Gitea's 4096-bit signatures already fill exactly. Entries are sorted by name, version, architecture and file
18
+ * name (bytewise), so the bytes depend on the entry set, not its order.
19
+ *
20
+ * Pure: the signer is the only call out. `timestamp` is validated but not
21
+ * written; the format carries no build time. An empty entry set returns `[]`.
22
+ * Bad input is `invalid-input` and names the entry; an error from the signer
23
+ * propagates unchanged; a signer result that is not non-empty bytes is
24
+ * `signing-failed`.
25
+ */
26
+ export declare function buildAlpineIndex(inputArg: {
27
+ branch: string;
28
+ repository: string;
29
+ entries: IAlpinePackageRecord[];
30
+ signer: IAlpineSigner;
31
+ timestamp: Date;
32
+ }): Promise<ILinuxIndexFile[]>;
33
+ /**
34
+ * One APKINDEX block for `recordArg` in the index of `architectureArg`, as
35
+ * Gitea writes it (`services/packages/alpine/repository.go:215-252`),
36
+ * including the blank line that ends it. Internal: 1.0.0 exports no
37
+ * per-entry renderers. The record must have passed `checkRecord`.
38
+ */
39
+ export declare function renderAlpineIndexEntry(recordArg: IAlpinePackageRecord, architectureArg: string): string;
@@ -0,0 +1,211 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { isIndexableArchitecture } from '../shared/architecture.js';
3
+ import { LinuxRepoError } from '../shared/errors.js';
4
+ import { assertSegmentName, assertString, assertTimestamp } from '../shared/validation.js';
5
+ import { concatBytes } from '../readers/bytes.js';
6
+ import { writeGoTar } from '../writers/gotar.js';
7
+ /** Gitea's `alpine_module.NoArch`: these packages are listed in every architecture's index too. */
8
+ const NOARCH = 'noarch';
9
+ const INDEX_FILE_NAME = 'APKINDEX';
10
+ const INDEX_ARCHIVE_NAME = 'APKINDEX.tar.gz';
11
+ const INDEX_MODE = 0o600;
12
+ const encoder = new TextEncoder();
13
+ /**
14
+ * Builds the `APKINDEX.tar.gz` set of one Alpine repository (one branch and
15
+ * repository) as Gitea 28.2.0 does (`services/packages/alpine/repository.go:150-351`):
16
+ * one index per architecture the entries name, at
17
+ * `{branch}/{repository}/{architecture}/APKINDEX.tar.gz`. Every index other
18
+ * than `noarch` also lists the `noarch` packages, and every block's `A:` is the
19
+ * index's architecture.
20
+ *
21
+ * Each archive is a signature gzip member (a tar entry
22
+ * `.SIGN.RSA.<signer.keyName>` holding RSA PKCS#1 v1.5 over SHA-1 of the
23
+ * unsigned stream, without an end-of-archive marker) followed by the unsigned
24
+ * gzip member (a tar entry `APKINDEX`, mode 0600, with the marker). Tar headers
25
+ * are byte-for-byte what Go `archive/tar` writes for Gitea (`writeGoTar`); the
26
+ * signature entry is padded to its 512-byte block (a difference from Gitea),
27
+ * which Gitea's 4096-bit signatures already fill exactly. Entries are sorted by name, version, architecture and file
28
+ * name (bytewise), so the bytes depend on the entry set, not its order.
29
+ *
30
+ * Pure: the signer is the only call out. `timestamp` is validated but not
31
+ * written; the format carries no build time. An empty entry set returns `[]`.
32
+ * Bad input is `invalid-input` and names the entry; an error from the signer
33
+ * propagates unchanged; a signer result that is not non-empty bytes is
34
+ * `signing-failed`.
35
+ */
36
+ export async function buildAlpineIndex(inputArg) {
37
+ if (inputArg === null || typeof inputArg !== 'object') {
38
+ throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
39
+ }
40
+ assertLayoutSegment(inputArg.branch, 'branch');
41
+ assertLayoutSegment(inputArg.repository, 'repository');
42
+ assertTimestamp(inputArg.timestamp);
43
+ const signer = inputArg.signer;
44
+ if (signer === null || typeof signer !== 'object' || typeof signer.sign !== 'function') {
45
+ throw new LinuxRepoError('invalid-input', 'signer must be an IAlpineSigner', { field: 'signer' });
46
+ }
47
+ assertSegmentName(signer.keyName, 'signer.keyName');
48
+ if (!Array.isArray(inputArg.entries)) {
49
+ throw new LinuxRepoError('invalid-input', 'entries must be an array', { field: 'entries' });
50
+ }
51
+ const entries = inputArg.entries.map((record, index) => checkRecord(record, `entries[${index}]`));
52
+ const seen = new Set();
53
+ for (const record of entries) {
54
+ const key = `${record.architecture}/${record.fileName}`;
55
+ if (seen.has(key)) {
56
+ throw new LinuxRepoError('invalid-input', `duplicate package file ${key}`, { field: 'entries', value: key });
57
+ }
58
+ seen.add(key);
59
+ }
60
+ entries.sort(compareRecords);
61
+ const architectures = [...new Set(entries.map((record) => record.architecture))].sort(compareBytes);
62
+ const files = [];
63
+ for (const architecture of architectures) {
64
+ const listed = entries.filter((record) => record.architecture === architecture || (architecture !== NOARCH && record.architecture === NOARCH));
65
+ const text = listed.map((record) => renderAlpineIndexEntry(record, architecture)).join('');
66
+ const unsigned = await gzip(writeGoTar([{ name: INDEX_FILE_NAME, mode: INDEX_MODE, data: encoder.encode(text) }], { endOfArchive: true }));
67
+ const signature = await signer.sign(unsigned);
68
+ if (!(signature instanceof Uint8Array) || signature.length === 0) {
69
+ throw new LinuxRepoError('signing-failed', 'the Alpine signer did not return signature bytes', {
70
+ field: 'signer',
71
+ });
72
+ }
73
+ const signatureMember = await gzip(writeGoTar([{ name: `.SIGN.RSA.${signer.keyName}`, mode: INDEX_MODE, data: signature }], { endOfArchive: false }));
74
+ const bytes = concatBytes([signatureMember, unsigned]);
75
+ files.push({
76
+ path: `${inputArg.branch}/${inputArg.repository}/${architecture}/${INDEX_ARCHIVE_NAME}`,
77
+ bytes,
78
+ sha256: plugins.crypto.createHash('sha256').update(bytes).digest('hex'),
79
+ mediaType: 'application/gzip',
80
+ stage: 'pointer',
81
+ aliases: [],
82
+ });
83
+ }
84
+ return files;
85
+ }
86
+ /**
87
+ * One APKINDEX block for `recordArg` in the index of `architectureArg`, as
88
+ * Gitea writes it (`services/packages/alpine/repository.go:215-252`),
89
+ * including the blank line that ends it. Internal: 1.0.0 exports no
90
+ * per-entry renderers. The record must have passed `checkRecord`.
91
+ */
92
+ export function renderAlpineIndexEntry(recordArg, architectureArg) {
93
+ const metadata = recordArg.metadata;
94
+ const lines = [
95
+ `C:Q1${Buffer.from(recordArg.digests.controlSha1, 'hex').toString('base64')}`,
96
+ `P:${recordArg.name}`,
97
+ `V:${recordArg.version}`,
98
+ `A:${architectureArg}`,
99
+ ];
100
+ if (metadata.description !== '') {
101
+ lines.push(`T:${metadata.description}`);
102
+ }
103
+ if (metadata.projectUrl !== '') {
104
+ lines.push(`U:${metadata.projectUrl}`);
105
+ }
106
+ if (metadata.license !== '') {
107
+ lines.push(`L:${metadata.license}`);
108
+ }
109
+ lines.push(`S:${recordArg.digests.size}`, `I:${metadata.installedSize}`, `o:${metadata.origin}`, `m:${metadata.maintainer}`, `t:${metadata.buildDate}`);
110
+ if (metadata.commit !== '') {
111
+ lines.push(`c:${metadata.commit}`);
112
+ }
113
+ if (metadata.dependencies.length > 0) {
114
+ lines.push(`D:${metadata.dependencies.join(' ')}`);
115
+ }
116
+ if (metadata.provides.length > 0) {
117
+ lines.push(`p:${metadata.provides.join(' ')}`);
118
+ }
119
+ if (metadata.installIf !== '') {
120
+ lines.push(`i:${metadata.installIf}`);
121
+ }
122
+ if (metadata.providerPriority > 0) {
123
+ lines.push(`k:${metadata.providerPriority}`);
124
+ }
125
+ return `${lines.join('\n')}\n\n`;
126
+ }
127
+ /**
128
+ * Checks what the index writes. A value with a line break would forge APKINDEX
129
+ * fields; Gitea's line-based `.PKGINFO` parser never produces one, so refusing
130
+ * it refuses no package Gitea stored.
131
+ */
132
+ function checkRecord(recordArg, fieldArg) {
133
+ const fail = (whatArg) => {
134
+ throw new LinuxRepoError('invalid-input', `${fieldArg}: ${whatArg}`, { field: fieldArg });
135
+ };
136
+ if (recordArg === null || typeof recordArg !== 'object') {
137
+ return fail('must be an Alpine package record');
138
+ }
139
+ const record = recordArg;
140
+ if (record.format !== 'alpine' || record.metadata === null || typeof record.metadata !== 'object') {
141
+ return fail('must be an Alpine package record');
142
+ }
143
+ if (record.digests === null || typeof record.digests !== 'object') {
144
+ return fail('digests must be an object');
145
+ }
146
+ const text = (valueArg, nameArg, nonEmptyArg = false) => {
147
+ if (typeof valueArg !== 'string' || /[\n]/.test(valueArg) || (nonEmptyArg && valueArg === '')) {
148
+ fail(`${nameArg} must be a${nonEmptyArg ? ' non-empty' : ''} string without line breaks`);
149
+ }
150
+ };
151
+ const integer = (valueArg, nameArg, minimumArg = -Number.MAX_SAFE_INTEGER) => {
152
+ if (typeof valueArg !== 'number' || !Number.isSafeInteger(valueArg) || valueArg < minimumArg) {
153
+ fail(`${nameArg} must be a safe integer${minimumArg === 0 ? ' >= 0' : ''}`);
154
+ }
155
+ };
156
+ const list = (valueArg, nameArg) => {
157
+ if (!Array.isArray(valueArg)) {
158
+ fail(`${nameArg} must be an array`);
159
+ }
160
+ valueArg.forEach((item, index) => text(item, `${nameArg}[${index}]`));
161
+ };
162
+ text(record.name, 'name', true);
163
+ text(record.version, 'version', true);
164
+ assertString(record.fileName, `${fieldArg}.fileName`);
165
+ if (!isIndexableArchitecture(record.architecture)) {
166
+ fail(`architecture ${JSON.stringify(record.architecture)} of ${record.fileName} cannot name an index`);
167
+ }
168
+ if (typeof record.digests.controlSha1 !== 'string' || !/^[0-9a-f]{40}$/.test(record.digests.controlSha1)) {
169
+ fail('digests.controlSha1 must be 40 lowercase hex digits');
170
+ }
171
+ integer(record.digests.size, 'digests.size', 0);
172
+ const metadata = record.metadata;
173
+ for (const key of ['description', 'license', 'projectUrl', 'maintainer', 'origin', 'commit', 'installIf']) {
174
+ text(metadata[key], `metadata.${key}`);
175
+ }
176
+ integer(metadata.installedSize, 'metadata.installedSize');
177
+ integer(metadata.buildDate, 'metadata.buildDate');
178
+ integer(metadata.providerPriority, 'metadata.providerPriority');
179
+ list(metadata.dependencies, 'metadata.dependencies');
180
+ list(metadata.provides, 'metadata.provides');
181
+ return record;
182
+ }
183
+ function assertLayoutSegment(valueArg, fieldArg) {
184
+ assertSegmentName(valueArg, fieldArg);
185
+ if (valueArg === '.' || valueArg === '..') {
186
+ throw new LinuxRepoError('invalid-input', `${fieldArg} must not be "." or ".."`, { field: fieldArg });
187
+ }
188
+ }
189
+ function compareRecords(aArg, bArg) {
190
+ return (compareBytes(aArg.name, bArg.name) ||
191
+ compareBytes(aArg.version, bArg.version) ||
192
+ compareBytes(aArg.architecture, bArg.architecture) ||
193
+ compareBytes(aArg.fileName, bArg.fileName));
194
+ }
195
+ /** Orders strings by their UTF-8 bytes. */
196
+ function compareBytes(aArg, bArg) {
197
+ return Buffer.compare(Buffer.from(aArg, 'utf8'), Buffer.from(bArg, 'utf8'));
198
+ }
199
+ function gzip(bytesArg) {
200
+ return new Promise((resolve, reject) => {
201
+ plugins.zlib.gzip(bytesArg, (error, result) => {
202
+ if (error) {
203
+ reject(error);
204
+ }
205
+ else {
206
+ resolve(new Uint8Array(result.buffer, result.byteOffset, result.byteLength));
207
+ }
208
+ });
209
+ });
210
+ }
211
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBraW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9hbHBpbmUvYXBraW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDcEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXJELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFM0YsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVqRCxtR0FBbUc7QUFDbkcsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDO0FBQ3hCLE1BQU0sZUFBZSxHQUFHLFVBQVUsQ0FBQztBQUNuQyxNQUFNLGtCQUFrQixHQUFHLGlCQUFpQixDQUFDO0FBQzdDLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQztBQUN6QixNQUFNLE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO0FBRWxDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxRQU10QztJQUNDLElBQUksUUFBUSxLQUFLLElBQUksSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUN0RCxNQUFNLElBQUksY0FBYyxDQUFDLGVBQWUsRUFBRSx5QkFBeUIsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFDRCxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQy9DLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsWUFBWSxDQUFD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
@@ -0,0 +1,45 @@
1
+ import type { ILinuxPackageLimits } from '../shared/limits.js';
2
+ /** What Gitea 28.2.0 derives from an apk `.PKGINFO` (`modules/packages/alpine/metadata.go:137-227`). */
3
+ export interface IAlpinePackageInfo {
4
+ name: string;
5
+ version: string;
6
+ architecture: string;
7
+ description: string;
8
+ license: string;
9
+ projectUrl: string;
10
+ maintainer: string;
11
+ packager: string;
12
+ buildDate: number;
13
+ installedSize: number;
14
+ origin: string;
15
+ commit: string;
16
+ installIf: string;
17
+ provides: string[];
18
+ dependencies: string[];
19
+ providerPriority: number;
20
+ }
21
+ /**
22
+ * Parses `.PKGINFO` as Gitea's `ParsePackageInfo` does:
23
+ * - lines split as `bufio.ScanLines` (LF, one trailing CR dropped, a final
24
+ * line without LF counts);
25
+ * - `#` lines and lines without `=` are skipped; key and value are
26
+ * `strings.TrimSpace`d around the first `=`; the last value wins, except
27
+ * `provides` and `depend`, which collect every non-empty value;
28
+ * - `builddate`, `size` and `provider_priority` are `strconv.ParseInt(v, 10,
29
+ * 64)`; a value Go cannot parse (including one outside int64) is ignored,
30
+ * so the field keeps its previous value, 0 when there is none
31
+ * (`metadata.go:165-174`, `:203-207`);
32
+ * - an empty `pkgname` or `pkgver` is refused; a `url` Gitea's URL validation
33
+ * refuses becomes `''`.
34
+ *
35
+ * Bytes are decoded with `decodeGoUtf8`. Where the codec differs from Gitea
36
+ * (test/test.alpine.reader.node.ts pins each case against Gitea's own code):
37
+ * - a line is bounded by `maxHeaderBytes` instead of Go's 64 KiB scanner buffer;
38
+ * - `provides` plus `depend` values are bounded by `maxEntries` instead of 1024;
39
+ * - invalid UTF-8 becomes U+FFFD per byte, where Gitea 28.2.0 refuses the
40
+ * upload because its `encoding/json/v2` cannot store the metadata;
41
+ * - a number Go parses but JSON cannot hold exactly (beyond
42
+ * `Number.MAX_SAFE_INTEGER` in magnitude) is refused as `invalid-field`,
43
+ * never rounded.
44
+ */
45
+ export declare function parseAlpinePackageInfo(bytesArg: Uint8Array, limitsArg: Readonly<ILinuxPackageLimits>): IAlpinePackageInfo;
@@ -0,0 +1,159 @@
1
+ import { LinuxRepoError, limitExceeded } from '../shared/errors.js';
2
+ import { goParseInt64, goTrimSpace } from '../shared/gostrings.js';
3
+ import { isValidUrl } from '../shared/url.js';
4
+ import { decodeGoUtf8 } from '../readers/text.js';
5
+ const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
6
+ /**
7
+ * Parses `.PKGINFO` as Gitea's `ParsePackageInfo` does:
8
+ * - lines split as `bufio.ScanLines` (LF, one trailing CR dropped, a final
9
+ * line without LF counts);
10
+ * - `#` lines and lines without `=` are skipped; key and value are
11
+ * `strings.TrimSpace`d around the first `=`; the last value wins, except
12
+ * `provides` and `depend`, which collect every non-empty value;
13
+ * - `builddate`, `size` and `provider_priority` are `strconv.ParseInt(v, 10,
14
+ * 64)`; a value Go cannot parse (including one outside int64) is ignored,
15
+ * so the field keeps its previous value, 0 when there is none
16
+ * (`metadata.go:165-174`, `:203-207`);
17
+ * - an empty `pkgname` or `pkgver` is refused; a `url` Gitea's URL validation
18
+ * refuses becomes `''`.
19
+ *
20
+ * Bytes are decoded with `decodeGoUtf8`. Where the codec differs from Gitea
21
+ * (test/test.alpine.reader.node.ts pins each case against Gitea's own code):
22
+ * - a line is bounded by `maxHeaderBytes` instead of Go's 64 KiB scanner buffer;
23
+ * - `provides` plus `depend` values are bounded by `maxEntries` instead of 1024;
24
+ * - invalid UTF-8 becomes U+FFFD per byte, where Gitea 28.2.0 refuses the
25
+ * upload because its `encoding/json/v2` cannot store the metadata;
26
+ * - a number Go parses but JSON cannot hold exactly (beyond
27
+ * `Number.MAX_SAFE_INTEGER` in magnitude) is refused as `invalid-field`,
28
+ * never rounded.
29
+ */
30
+ export function parseAlpinePackageInfo(bytesArg, limitsArg) {
31
+ const info = {
32
+ name: '',
33
+ version: '',
34
+ architecture: '',
35
+ description: '',
36
+ license: '',
37
+ projectUrl: '',
38
+ maintainer: '',
39
+ packager: '',
40
+ buildDate: 0,
41
+ installedSize: 0,
42
+ origin: '',
43
+ commit: '',
44
+ installIf: '',
45
+ provides: [],
46
+ dependencies: [],
47
+ providerPriority: 0,
48
+ };
49
+ for (const line of scanLines(bytesArg, limitsArg.maxHeaderBytes)) {
50
+ if (line.startsWith('#')) {
51
+ continue;
52
+ }
53
+ const equals = line.indexOf('=');
54
+ if (equals < 0) {
55
+ continue;
56
+ }
57
+ const key = goTrimSpace(line.slice(0, equals));
58
+ const value = goTrimSpace(line.slice(equals + 1));
59
+ switch (key) {
60
+ case 'pkgname':
61
+ info.name = value;
62
+ break;
63
+ case 'pkgver':
64
+ info.version = value;
65
+ break;
66
+ case 'pkgdesc':
67
+ info.description = value;
68
+ break;
69
+ case 'url':
70
+ info.projectUrl = value;
71
+ break;
72
+ case 'builddate':
73
+ info.buildDate = goParseInt(value, key) ?? info.buildDate;
74
+ break;
75
+ case 'size':
76
+ info.installedSize = goParseInt(value, key) ?? info.installedSize;
77
+ break;
78
+ case 'arch':
79
+ info.architecture = value;
80
+ break;
81
+ case 'origin':
82
+ info.origin = value;
83
+ break;
84
+ case 'commit':
85
+ info.commit = value;
86
+ break;
87
+ case 'maintainer':
88
+ info.maintainer = value;
89
+ break;
90
+ case 'packager':
91
+ info.packager = value;
92
+ break;
93
+ case 'license':
94
+ info.license = value;
95
+ break;
96
+ case 'install_if':
97
+ info.installIf = value;
98
+ break;
99
+ case 'provides':
100
+ case 'depend':
101
+ if (value !== '') {
102
+ if (info.provides.length + info.dependencies.length >= limitsArg.maxEntries) {
103
+ throw limitExceeded('maxEntries', limitsArg.maxEntries, '.PKGINFO provides and depend values');
104
+ }
105
+ (key === 'provides' ? info.provides : info.dependencies).push(value);
106
+ }
107
+ break;
108
+ case 'provider_priority':
109
+ info.providerPriority = goParseInt(value, key) ?? info.providerPriority;
110
+ break;
111
+ }
112
+ }
113
+ if (info.name === '') {
114
+ throw new LinuxRepoError('missing-field', '.PKGINFO has no pkgname', { field: 'pkgname' });
115
+ }
116
+ if (info.version === '') {
117
+ throw new LinuxRepoError('missing-field', '.PKGINFO has no pkgver', { field: 'pkgver' });
118
+ }
119
+ if (!isValidUrl(info.projectUrl)) {
120
+ info.projectUrl = '';
121
+ }
122
+ return info;
123
+ }
124
+ /** `bufio.ScanLines` over the bytes, each line decoded as Gitea stores it. */
125
+ function* scanLines(bytesArg, maxLineBytesArg) {
126
+ let start = 0;
127
+ while (start < bytesArg.length) {
128
+ const newline = bytesArg.indexOf(0x0a, start);
129
+ const end = newline < 0 ? bytesArg.length : newline;
130
+ let lineEnd = end;
131
+ if (lineEnd > start && bytesArg[lineEnd - 1] === 0x0d) {
132
+ lineEnd -= 1;
133
+ }
134
+ if (lineEnd - start > maxLineBytesArg) {
135
+ throw limitExceeded('maxHeaderBytes', maxLineBytesArg, '.PKGINFO line');
136
+ }
137
+ yield decodeGoUtf8(bytesArg.subarray(start, lineEnd));
138
+ start = newline < 0 ? bytesArg.length : newline + 1;
139
+ }
140
+ }
141
+ /**
142
+ * Go `strconv.ParseInt(value, 10, 64)`: `null` where Go returns an error (Gitea
143
+ * then keeps the previous value); `invalid-field` for an int64 beyond the safe
144
+ * JSON integer range.
145
+ */
146
+ function goParseInt(valueArg, fieldArg) {
147
+ const value = goParseInt64(valueArg);
148
+ if (value === null) {
149
+ return null;
150
+ }
151
+ if (value > MAX_SAFE || value < -MAX_SAFE) {
152
+ throw new LinuxRepoError('invalid-field', `.PKGINFO ${fieldArg} is beyond the safe integer range`, {
153
+ field: fieldArg,
154
+ value: valueArg,
155
+ });
156
+ }
157
+ return Number(value) + 0;
158
+ }
159
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGtnaW5mby5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FscGluZS9wa2dpbmZvLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFcEUsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDOUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBc0JsRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFFakQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUFDLFFBQW9CLEVBQUUsU0FBd0M7SUFDbkcsTUFBTSxJQUFJLEdBQXVCO1FBQy9CLElBQUksRUFBRSxFQUFFO1FBQ1IsT0FBTyxFQUFFLEVBQUU7UUFDWCxZQUFZLEVBQUUsRUFBRTtRQUNoQixXQUFXLEVBQUUsRUFBRTtRQUNmLE9BQU8sRUFBRSxFQUFFO1FBQ1gsVUFBVSxFQUFFLEVBQUU7UUFDZCxVQUFVLEVBQUUsRUFBRTtRQUNkLFFBQVEsRUFBRSxFQUFFO1FBQ1osU0FBUyxFQUFFLENBQUM7UUFDWixhQUFhLEVBQUUsQ0FBQztRQUNoQixNQUFNLEVBQUUsRUFBRTtRQUNWLE1BQU0sRUFBRSxFQUFFO1FBQ1YsU0FBUyxFQUFFLEVBQUU7UUFDYixRQUFRLEVBQUUsRUFBRTtRQUNaLFlBQVksRUFBRSxFQUFFO1FBQ2hCLGdCQUFnQixFQUFFLENBQUM7S0FDcEIsQ0FBQztJQUNGLEtBQUssTUFBTSxJQUFJLElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztRQUNqRSxJQUFJLElBQUksQ0FBQyxVQUFV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
@@ -0,0 +1,20 @@
1
+ import { type ILinuxPackageLimits } from '../shared/limits.js';
2
+ import type { IAlpinePackageRecord } from '../shared/types.js';
3
+ /**
4
+ * Reads an apk v2 package (concatenated gzip members: usually the signature,
5
+ * the control segment holding `.PKGINFO`, and the data) into a record, as
6
+ * Gitea 28.2.0's `ParsePackage` does (`modules/packages/alpine/metadata.go:77-134`):
7
+ * - gzip members are read one at a time; the first member whose tar holds an
8
+ * entry named exactly `.PKGINFO` is the control segment. Unsigned packages
9
+ * (no signature member) are accepted;
10
+ * - `digests.controlSha1` is the SHA-1 of exactly that member's bytes (the
11
+ * APKINDEX `C:` value is `Q1` plus its base64);
12
+ * - the rest of the input is hashed, never decompressed;
13
+ * - the record's `fileName` is Gitea's `{name}-{version}.apk`.
14
+ *
15
+ * Each member read before the control segment is buffered and bounded by
16
+ * `maxMetadataBytes` (member bytes) and `maxDecompressedMetadataBytes` (its
17
+ * tar). An apk v3 (ADB) package is `unsupported-package-format`, as Gitea
18
+ * refuses it too. On failure the reader stops pulling and returns no record.
19
+ */
20
+ export declare function readAlpinePackage(sourceArg: AsyncIterable<Uint8Array>, limitsArg?: Partial<ILinuxPackageLimits>): Promise<IAlpinePackageRecord>;