@push.rocks/smartlinuxrepo 0.0.0-stage → 0.1.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 +64 -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,183 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { PackageByteSource } from '../readers/bytesource.js';
3
+ import { READ_CHUNK_BYTES } from '../readers/bytes.js';
4
+ import { LinuxRepoError } from '../shared/errors.js';
5
+ import { resolveLinuxPackageLimits } from '../shared/limits.js';
6
+ import { assertTimestamp } from '../shared/validation.js';
7
+ import { createDetachedBinarySignature } from '../signing/openpgpframing.js';
8
+ import { singleChunk } from '../signing/signers.js';
9
+ import { readRpmHeaders, RPM_SIGNATURE_TAG, RPM_TYPE, writeSignatureHeader } from './header.js';
10
+ const PAYLOAD_DIGEST = 5092;
11
+ const PAYLOAD_DIGEST_ALGORITHM = 5093;
12
+ /** go-rpmutils `getPayloadDigest` algorithms (`signatures.go`, RFC 4880 ids). */
13
+ const PAYLOAD_DIGEST_ALGORITHMS = new Map([
14
+ [1, 'md5'],
15
+ [2, 'sha1'],
16
+ [8, 'sha256'],
17
+ [9, 'sha384'],
18
+ [10, 'sha512'],
19
+ [11, 'sha224'],
20
+ ]);
21
+ /**
22
+ * Signs an RPM package as Gitea 28.2.0 does on upload (`services/packages/rpm/sign.go:17-38`,
23
+ * go-rpmutils v0.4.0 `SignRpmStream` and `DumpSignatureHeader(false)`):
24
+ * - the main header digest is checked, and the payload is checked against
25
+ * PAYLOADDIGEST (5092/5093), else the signature header MD5 (1004) over
26
+ * header and payload; a package with neither is `missing-field`, a mismatch
27
+ * `digest-mismatch`;
28
+ * - tag 1002 gets a signature over the main header and payload, tag 268 one
29
+ * over the main header alone; tags 1005, 267 and 1008 are removed; every
30
+ * other signature tag from 64 up is kept byte for byte, the tags are written
31
+ * in ascending order behind a new region tag 62, and the header is padded to
32
+ * 8 bytes.
33
+ *
34
+ * The signed package is `prefix` (the lead and the new signature header)
35
+ * followed by the original bytes from `resumeAt`, the start of the main
36
+ * header. The source is read once; only the headers are held in memory, and
37
+ * the payload streams through the signer. A signer that returns before reading
38
+ * the data to its end is `signing-failed`.
39
+ */
40
+ export async function signRpmPackage(input) {
41
+ if (input === null || typeof input !== 'object') {
42
+ throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
43
+ }
44
+ if (input.signer === null || typeof input.signer !== 'object' || typeof input.signer.signBinary !== 'function') {
45
+ throw new LinuxRepoError('invalid-input', 'signer must implement IOpenPgpSigner', { field: 'signer' });
46
+ }
47
+ assertTimestamp(input.timestamp);
48
+ const limits = resolveLinuxPackageLimits(input.limits);
49
+ const bytes = new PackageByteSource(input.source, limits.maxPackageBytes);
50
+ const headers = await readRpmHeaders(bytes, limits);
51
+ const payloadCheck = payloadDigestCheck(headers);
52
+ const signedData = new SignedDataStream(headers.main.bytes, bytes, payloadCheck);
53
+ let headerAndPayload;
54
+ try {
55
+ headerAndPayload = await createDetachedBinarySignature({ data: signedData, signer: input.signer, timestamp: input.timestamp });
56
+ }
57
+ catch (error) {
58
+ // a failure of the codec's own stream (or the caller's source) wins over what the signer made of it
59
+ throw signedData.failure !== undefined ? signedData.failure.error : error;
60
+ }
61
+ if (signedData.failure !== undefined) {
62
+ throw signedData.failure.error;
63
+ }
64
+ if (!signedData.completed) {
65
+ throw new LinuxRepoError('signing-failed', 'the signer returned before reading the package to its end', { field: 'signer' });
66
+ }
67
+ const headerOnly = await createDetachedBinarySignature({
68
+ data: singleChunk(headers.main.bytes),
69
+ signer: input.signer,
70
+ timestamp: input.timestamp,
71
+ });
72
+ const removed = new Set([
73
+ RPM_SIGNATURE_TAG.pgp,
74
+ RPM_SIGNATURE_TAG.rsa,
75
+ RPM_SIGNATURE_TAG.gpg,
76
+ RPM_SIGNATURE_TAG.dsa,
77
+ RPM_SIGNATURE_TAG.reservedSpace,
78
+ ]);
79
+ const signatureHeader = writeSignatureHeader(headers.signature, removed, [
80
+ { tag: RPM_SIGNATURE_TAG.pgp, type: RPM_TYPE.bin, count: headerAndPayload.length, contents: headerAndPayload },
81
+ { tag: RPM_SIGNATURE_TAG.rsa, type: RPM_TYPE.bin, count: headerOnly.length, contents: headerOnly },
82
+ ]);
83
+ const prefix = new Uint8Array(headers.lead.length + signatureHeader.length);
84
+ prefix.set(headers.lead, 0);
85
+ prefix.set(signatureHeader, headers.lead.length);
86
+ return { prefix, resumeAt: headers.mainStart };
87
+ }
88
+ function payloadDigestCheck(headersArg) {
89
+ // the same lookups, in the same order, as go-rpmutils `getPayloadDigest`
90
+ const digests = headersArg.main.strings(PAYLOAD_DIGEST);
91
+ const algorithms = digests === null || digests.length === 0 ? null : headersArg.main.uint32s(PAYLOAD_DIGEST_ALGORITHM);
92
+ const algorithm = algorithms === null || algorithms.length === 0 ? undefined : PAYLOAD_DIGEST_ALGORITHMS.get(algorithms[0]);
93
+ if (algorithm !== undefined && digests !== null) {
94
+ const expected = digests[0];
95
+ return {
96
+ hash: plugins.crypto.createHash(algorithm),
97
+ coversHeader: false,
98
+ matches: (digestArg) => {
99
+ const actual = new TextEncoder().encode(digestArg.toString('hex'));
100
+ return actual.length === expected.length && actual.every((byte, i) => byte === expected[i]);
101
+ },
102
+ };
103
+ }
104
+ const md5 = headersArg.signature.binary(RPM_SIGNATURE_TAG.md5);
105
+ if (md5 !== null && md5.length !== 0) {
106
+ return {
107
+ hash: plugins.crypto.createHash('md5'),
108
+ coversHeader: true,
109
+ matches: (digestArg) => digestArg.length === md5.length && digestArg.every((byte, i) => byte === md5[i]),
110
+ };
111
+ }
112
+ throw new LinuxRepoError('missing-field', 'the RPM package has no usable payload digest', { field: 'payload digest' });
113
+ }
114
+ /**
115
+ * The data tag 1002 signs: the main header, then the payload as it is pulled
116
+ * from the package source, hashed for the payload check on the way. Iterable
117
+ * once; it pulls only when the signer asks. Any failure (the caller's source,
118
+ * a limit, truncation, a digest mismatch) is thrown to the signer and kept, so
119
+ * `signRpmPackage` reports it instead of whatever the signer made of it.
120
+ */
121
+ class SignedDataStream {
122
+ mainHeader;
123
+ source;
124
+ check;
125
+ completed = false;
126
+ failure = undefined;
127
+ iterated = false;
128
+ headerSent = false;
129
+ queue = Promise.resolve();
130
+ constructor(mainHeader, source, check) {
131
+ this.mainHeader = mainHeader;
132
+ this.source = source;
133
+ this.check = check;
134
+ }
135
+ [Symbol.asyncIterator]() {
136
+ if (this.iterated) {
137
+ const error = new LinuxRepoError('signing-failed', 'the signer read the package data more than once', { field: 'signer' });
138
+ this.failure ??= { error };
139
+ throw error;
140
+ }
141
+ this.iterated = true;
142
+ return {
143
+ next: () => {
144
+ // serialize: a signer that does not await one next() before the next one still gets the bytes in order
145
+ const result = this.queue.then(() => this.pull());
146
+ this.queue = result.catch(() => undefined);
147
+ return result;
148
+ },
149
+ };
150
+ }
151
+ async pull() {
152
+ if (this.failure !== undefined) {
153
+ throw this.failure.error;
154
+ }
155
+ if (this.completed) {
156
+ return { done: true, value: undefined };
157
+ }
158
+ try {
159
+ if (!this.headerSent) {
160
+ this.headerSent = true;
161
+ if (this.check.coversHeader) {
162
+ this.check.hash.update(this.mainHeader);
163
+ }
164
+ return { done: false, value: this.mainHeader };
165
+ }
166
+ const chunk = await this.source.read(READ_CHUNK_BYTES);
167
+ if (chunk !== null) {
168
+ this.check.hash.update(chunk);
169
+ return { done: false, value: chunk };
170
+ }
171
+ if (!this.check.matches(this.check.hash.digest())) {
172
+ throw new LinuxRepoError('digest-mismatch', 'the RPM payload does not match its digest', { field: 'payload digest' });
173
+ }
174
+ this.completed = true;
175
+ return { done: true, value: undefined };
176
+ }
177
+ catch (error) {
178
+ this.failure = { error };
179
+ throw error;
180
+ }
181
+ }
182
+ }
183
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3JwbS9zaWduLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzdELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUseUJBQXlCLEVBQTRCLE1BQU0scUJBQXFCLENBQUM7QUFDMUYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzFELE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQXVCLE1BQU0sdUJBQXVCLENBQUM7QUFDekUsT0FBTyxFQUFFLGNBQWMsRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsb0JBQW9CLEVBQTJCLE1BQU0sYUFBYSxDQUFDO0FBRXpILE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQztBQUM1QixNQUFNLHdCQUF3QixHQUFHLElBQUksQ0FBQztBQUV0QyxpRkFBaUY7QUFDakYsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLEdBQUcsQ0FBaUI7SUFDeEQsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ1YsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ1gsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDO0lBQ2IsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDO0lBQ2IsQ0FBQyxFQUFFLEVBQUUsUUFBUSxDQUFDO0lBQ2QsQ0FBQyxFQUFFLEVBQUUsUUFBUSxDQUFDO0NBQ2YsQ0FBQyxDQUFDO0FBRUg7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsY0FBYyxDQUFD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
@@ -0,0 +1,38 @@
1
+ import type { IRpmUpdate } from '../shared/types.js';
2
+ /**
3
+ * Merges posted errata into the stored ones, as Gitea 28.2.0's errata route
4
+ * does (`routers/api/packages/rpm/rpm.go:367-447`). Pure: the inputs are
5
+ * never changed, and incoming updates are applied in order.
6
+ * - A known id: its collections merge by `short` and its packages are
7
+ * de-duplicated by name, version, release and arch; the seven scalar fields
8
+ * and `references` are replaced; `updated` becomes the timestamp and
9
+ * `issued` is kept.
10
+ * - A new id: the update is appended; `issued` and `updated` get the
11
+ * timestamp only when they are `null`.
12
+ * - De-duplication applies to every append, including the collections of a new
13
+ * update (Gitea appends those as posted).
14
+ * Dates are written as `YYYY-MM-DD HH:MM:SS` in UTC (Gitea uses its server's
15
+ * local time). Contents are not validated, as in Gitea; only the shape is.
16
+ */
17
+ export declare function mergeRpmUpdates(input: {
18
+ existing: IRpmUpdate[];
19
+ incoming: IRpmUpdate[];
20
+ timestamp: Date;
21
+ }): IRpmUpdate[];
22
+ /**
23
+ * The updates of an index: updates with the same id merge as
24
+ * Gitea's `buildUpdateInfo` does (`services/packages/rpm/repository.go:560-620`),
25
+ * without setting any date. The scalar fields, dates and references come from
26
+ * the update with the newest `updated`, then the newest `issued`, then the
27
+ * greatest canonical JSON of those fields; packages that collide keep the
28
+ * values of the higher-ranked update. Updates sort by id, collections by
29
+ * `short`, packages by name, version, release and arch; references keep their
30
+ * order. The input order never decides.
31
+ */
32
+ export declare function combineRpmUpdates(updatesArg: IRpmUpdate[]): IRpmUpdate[];
33
+ /** `updateinfo.xml` for combined updates, as Go's `encoding/xml` writes Gitea's `Update` type. */
34
+ export declare function renderUpdateInfo(updatesArg: IRpmUpdate[]): string;
35
+ /** `YYYY-MM-DD HH:MM:SS` in UTC. */
36
+ export declare function formatRpmUpdateDate(timestampArg: Date): string;
37
+ /** Refuses anything that is not an array of plain-JSON `IRpmUpdate` values. */
38
+ export declare function assertRpmUpdates(valueArg: unknown, fieldArg: string): asserts valueArg is IRpmUpdate[];
@@ -0,0 +1,265 @@
1
+ import { LinuxRepoError } from '../shared/errors.js';
2
+ import { assertTimestamp } from '../shared/validation.js';
3
+ import { compareCodePoints, element, textElement, XML_HEADER } from './xml.js';
4
+ /**
5
+ * Merges posted errata into the stored ones, as Gitea 28.2.0's errata route
6
+ * does (`routers/api/packages/rpm/rpm.go:367-447`). Pure: the inputs are
7
+ * never changed, and incoming updates are applied in order.
8
+ * - A known id: its collections merge by `short` and its packages are
9
+ * de-duplicated by name, version, release and arch; the seven scalar fields
10
+ * and `references` are replaced; `updated` becomes the timestamp and
11
+ * `issued` is kept.
12
+ * - A new id: the update is appended; `issued` and `updated` get the
13
+ * timestamp only when they are `null`.
14
+ * - De-duplication applies to every append, including the collections of a new
15
+ * update (Gitea appends those as posted).
16
+ * Dates are written as `YYYY-MM-DD HH:MM:SS` in UTC (Gitea uses its server's
17
+ * local time). Contents are not validated, as in Gitea; only the shape is.
18
+ */
19
+ export function mergeRpmUpdates(input) {
20
+ if (input === null || typeof input !== 'object') {
21
+ throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
22
+ }
23
+ assertRpmUpdates(input.existing, 'existing');
24
+ assertRpmUpdates(input.incoming, 'incoming');
25
+ assertTimestamp(input.timestamp);
26
+ const now = formatRpmUpdateDate(input.timestamp);
27
+ const merged = input.existing.map(cloneUpdate);
28
+ for (const incoming of input.incoming) {
29
+ const update = cloneUpdate(incoming);
30
+ const known = merged.find((candidate) => candidate.id === update.id);
31
+ if (known !== undefined) {
32
+ mergeCollections(known.collections, update.collections);
33
+ known.from = update.from;
34
+ known.status = update.status;
35
+ known.type = update.type;
36
+ known.version = update.version;
37
+ known.title = update.title;
38
+ known.severity = update.severity;
39
+ known.description = update.description;
40
+ known.references = update.references;
41
+ known.updated = now;
42
+ }
43
+ else {
44
+ const appended = { ...update, issued: update.issued ?? now, updated: update.updated ?? now, collections: [] };
45
+ mergeCollections(appended.collections, update.collections);
46
+ merged.push(appended);
47
+ }
48
+ }
49
+ return merged;
50
+ }
51
+ /**
52
+ * The updates of an index: updates with the same id merge as
53
+ * Gitea's `buildUpdateInfo` does (`services/packages/rpm/repository.go:560-620`),
54
+ * without setting any date. The scalar fields, dates and references come from
55
+ * the update with the newest `updated`, then the newest `issued`, then the
56
+ * greatest canonical JSON of those fields; packages that collide keep the
57
+ * values of the higher-ranked update. Updates sort by id, collections by
58
+ * `short`, packages by name, version, release and arch; references keep their
59
+ * order. The input order never decides.
60
+ */
61
+ export function combineRpmUpdates(updatesArg) {
62
+ const byId = new Map();
63
+ for (const update of updatesArg) {
64
+ const group = byId.get(update.id);
65
+ if (group === undefined) {
66
+ byId.set(update.id, [update]);
67
+ }
68
+ else {
69
+ group.push(update);
70
+ }
71
+ }
72
+ const combined = [];
73
+ for (const group of byId.values()) {
74
+ const ranked = [...group].sort(compareRank);
75
+ const result = { ...cloneUpdate(ranked[0]), collections: [] };
76
+ for (const update of ranked) {
77
+ mergeCollections(result.collections, update.collections.map(cloneCollection));
78
+ }
79
+ result.collections.sort((a, b) => compareCodePoints(a.short, b.short));
80
+ for (const collection of result.collections) {
81
+ collection.packages.sort(comparePackages);
82
+ }
83
+ combined.push(result);
84
+ }
85
+ return combined.sort((a, b) => compareCodePoints(a.id, b.id));
86
+ }
87
+ /** `updateinfo.xml` for combined updates, as Go's `encoding/xml` writes Gitea's `Update` type. */
88
+ export function renderUpdateInfo(updatesArg) {
89
+ const updates = updatesArg.map((update) => element('update', [
90
+ ['from', update.from],
91
+ ['status', update.status],
92
+ ['type', update.type],
93
+ ['version', update.version],
94
+ ], [
95
+ textElement('id', update.id),
96
+ textElement('title', update.title),
97
+ textElement('severity', update.severity),
98
+ textElement('description', update.description),
99
+ update.issued === null ? '' : element('issued', [['date', update.issued]]),
100
+ update.updated === null ? '' : element('updated', [['date', update.updated]]),
101
+ element('references', [], update.references
102
+ .map((reference) => element('reference', [
103
+ ['href', reference.href],
104
+ ['id', reference.id],
105
+ ['title', reference.title],
106
+ ['type', reference.type],
107
+ ]))
108
+ .join('')),
109
+ element('pkglist', [], update.collections
110
+ .map((collection) => element('collection', [['short', collection.short]], collection.packages
111
+ .map((pkg) => element('package', [
112
+ ['arch', pkg.arch],
113
+ ['name', pkg.name],
114
+ ['release', pkg.release],
115
+ ['src', pkg.src],
116
+ ['version', pkg.version],
117
+ ], textElement('filename', pkg.fileName)))
118
+ .join('')))
119
+ .join('')),
120
+ ].join('')));
121
+ return `${XML_HEADER}${element('updates', [['xmlns', 'http://linux.duke.edu/metadata/updateinfo']], updates.join(''))}`;
122
+ }
123
+ /** `YYYY-MM-DD HH:MM:SS` in UTC. */
124
+ export function formatRpmUpdateDate(timestampArg) {
125
+ return timestampArg.toISOString().slice(0, 19).replace('T', ' ');
126
+ }
127
+ /** Refuses anything that is not an array of plain-JSON `IRpmUpdate` values. */
128
+ export function assertRpmUpdates(valueArg, fieldArg) {
129
+ if (!Array.isArray(valueArg)) {
130
+ throw new LinuxRepoError('invalid-input', `${fieldArg} must be an array of RPM updates`, { field: fieldArg });
131
+ }
132
+ valueArg.forEach((update, i) => {
133
+ const at = `${fieldArg}[${i}]`;
134
+ const record = assertObject(update, at);
135
+ for (const key of ['id', 'from', 'status', 'type', 'version', 'title', 'severity', 'description']) {
136
+ assertStringField(record, key, at);
137
+ }
138
+ for (const key of ['issued', 'updated']) {
139
+ if (record[key] !== null) {
140
+ assertStringField(record, key, at);
141
+ }
142
+ }
143
+ assertArrayField(record, 'references', at).forEach((reference, r) => {
144
+ const referenceRecord = assertObject(reference, `${at}.references[${r}]`);
145
+ for (const key of ['href', 'id', 'title', 'type']) {
146
+ assertStringField(referenceRecord, key, `${at}.references[${r}]`);
147
+ }
148
+ });
149
+ assertArrayField(record, 'collections', at).forEach((collection, c) => {
150
+ const collectionAt = `${at}.collections[${c}]`;
151
+ const collectionRecord = assertObject(collection, collectionAt);
152
+ assertStringField(collectionRecord, 'short', collectionAt);
153
+ assertArrayField(collectionRecord, 'packages', collectionAt).forEach((pkg, p) => {
154
+ const pkgRecord = assertObject(pkg, `${collectionAt}.packages[${p}]`);
155
+ for (const key of ['name', 'version', 'release', 'arch', 'src', 'fileName']) {
156
+ assertStringField(pkgRecord, key, `${collectionAt}.packages[${p}]`);
157
+ }
158
+ });
159
+ });
160
+ });
161
+ }
162
+ function assertObject(valueArg, fieldArg) {
163
+ if (valueArg === null || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
164
+ throw new LinuxRepoError('invalid-input', `${fieldArg} must be an object`, { field: fieldArg });
165
+ }
166
+ return valueArg;
167
+ }
168
+ function assertStringField(recordArg, keyArg, atArg) {
169
+ if (typeof recordArg[keyArg] !== 'string') {
170
+ throw new LinuxRepoError('invalid-input', `${atArg}.${keyArg} must be a string`, { field: `${atArg}.${keyArg}` });
171
+ }
172
+ }
173
+ function assertArrayField(recordArg, keyArg, atArg) {
174
+ const value = recordArg[keyArg];
175
+ if (!Array.isArray(value)) {
176
+ throw new LinuxRepoError('invalid-input', `${atArg}.${keyArg} must be an array`, { field: `${atArg}.${keyArg}` });
177
+ }
178
+ return value;
179
+ }
180
+ /** Merges `incomingArg` into `targetArg` by `short`, de-duplicating packages (mutates the target only). */
181
+ function mergeCollections(targetArg, incomingArg) {
182
+ for (const collection of incomingArg) {
183
+ let target = targetArg.find((candidate) => candidate.short === collection.short);
184
+ if (target === undefined) {
185
+ target = { short: collection.short, packages: [] };
186
+ targetArg.push(target);
187
+ }
188
+ for (const pkg of collection.packages) {
189
+ if (!target.packages.some((candidate) => samePackage(candidate, pkg))) {
190
+ target.packages.push(clonePackage(pkg));
191
+ }
192
+ }
193
+ }
194
+ }
195
+ function samePackage(aArg, bArg) {
196
+ return aArg.name === bArg.name && aArg.version === bArg.version && aArg.release === bArg.release && aArg.arch === bArg.arch;
197
+ }
198
+ function comparePackages(aArg, bArg) {
199
+ return (compareCodePoints(aArg.name, bArg.name) ||
200
+ compareCodePoints(aArg.version, bArg.version) ||
201
+ compareCodePoints(aArg.release, bArg.release) ||
202
+ compareCodePoints(aArg.arch, bArg.arch));
203
+ }
204
+ /** Highest rank first: newest `updated`, newest `issued`, greatest canonical JSON. */
205
+ function compareRank(aArg, bArg) {
206
+ return (compareNullableDesc(aArg.updated, bArg.updated) ||
207
+ compareNullableDesc(aArg.issued, bArg.issued) ||
208
+ compareCodePoints(canonicalScalars(bArg), canonicalScalars(aArg)));
209
+ }
210
+ function compareNullableDesc(aArg, bArg) {
211
+ if (aArg === bArg) {
212
+ return 0;
213
+ }
214
+ if (aArg === null) {
215
+ return 1;
216
+ }
217
+ if (bArg === null) {
218
+ return -1;
219
+ }
220
+ return compareCodePoints(bArg, aArg);
221
+ }
222
+ function canonicalScalars(updateArg) {
223
+ return JSON.stringify([
224
+ updateArg.from,
225
+ updateArg.status,
226
+ updateArg.type,
227
+ updateArg.version,
228
+ updateArg.title,
229
+ updateArg.severity,
230
+ updateArg.description,
231
+ updateArg.issued,
232
+ updateArg.updated,
233
+ updateArg.references.map((reference) => [reference.href, reference.id, reference.title, reference.type]),
234
+ ]);
235
+ }
236
+ function cloneUpdate(updateArg) {
237
+ return {
238
+ id: updateArg.id,
239
+ from: updateArg.from,
240
+ status: updateArg.status,
241
+ type: updateArg.type,
242
+ version: updateArg.version,
243
+ title: updateArg.title,
244
+ severity: updateArg.severity,
245
+ description: updateArg.description,
246
+ issued: updateArg.issued,
247
+ updated: updateArg.updated,
248
+ references: updateArg.references.map((reference) => ({ href: reference.href, id: reference.id, title: reference.title, type: reference.type })),
249
+ collections: updateArg.collections.map(cloneCollection),
250
+ };
251
+ }
252
+ function cloneCollection(collectionArg) {
253
+ return { short: collectionArg.short, packages: collectionArg.packages.map(clonePackage) };
254
+ }
255
+ function clonePackage(pkgArg) {
256
+ return {
257
+ name: pkgArg.name,
258
+ version: pkgArg.version,
259
+ release: pkgArg.release,
260
+ arch: pkgArg.arch,
261
+ src: pkgArg.src,
262
+ fileName: pkgArg.fileName,
263
+ };
264
+ }
265
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3JwbS91cGRhdGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVyRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRS9FOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUEwRTtJQUN4RyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDaEQsTUFBTSxJQUFJLGNBQWMsQ0FBQyxlQUFlLEVBQUUseUJBQXlCLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBQ0QsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUM3QyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzdDLGVBQWUsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDakMsTUFBTSxHQUFHLEdBQUcsbUJBQW1CLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2pELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLEtBQUssTUFBTSxRQUFRLElBQUksS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFF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
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The XML output of Go's `encoding/xml` as Gitea 28.2.0 uses it: the header
3
+ * `xml.Header`, no indentation, no self-closing elements, attributes in struct
4
+ * field order, and Go's escaping (`EscapeText`/`EscapeString`): `"` and `'`
5
+ * become numeric references, tab, line feed and carriage return are escaped,
6
+ * and a code point outside the XML character range becomes U+FFFD.
7
+ */
8
+ export declare const XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
9
+ /** Go's escaping of character data and attribute values. */
10
+ export declare function escapeXml(valueArg: string): string;
11
+ /** Attributes in order; a value of `undefined` is omitted (Go's `omitempty` for an empty string is the caller's choice). */
12
+ export type TXmlAttributes = Array<[string, string | number | undefined]>;
13
+ /** `<name attr="…">content</name>`, where `contentArg` is already XML. */
14
+ export declare function element(nameArg: string, attributesArg: TXmlAttributes, contentArg?: string): string;
15
+ /** `<name>escaped text</name>`. */
16
+ export declare function textElement(nameArg: string, textArg: string, attributesArg?: TXmlAttributes): string;
17
+ /** Go's `strings.Compare`: UTF-8 byte order, which is code point order. */
18
+ export declare function compareCodePoints(aArg: string, bArg: string): number;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The XML output of Go's `encoding/xml` as Gitea 28.2.0 uses it: the header
3
+ * `xml.Header`, no indentation, no self-closing elements, attributes in struct
4
+ * field order, and Go's escaping (`EscapeText`/`EscapeString`): `"` and `'`
5
+ * become numeric references, tab, line feed and carriage return are escaped,
6
+ * and a code point outside the XML character range becomes U+FFFD.
7
+ */
8
+ export const XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n';
9
+ const NEEDS_ESCAPE = /["'&<>\u0000-\u001f\ud800-\udfff\ufffe\uffff]/;
10
+ /** Go's escaping of character data and attribute values. */
11
+ export function escapeXml(valueArg) {
12
+ if (!NEEDS_ESCAPE.test(valueArg)) {
13
+ return valueArg;
14
+ }
15
+ let result = '';
16
+ for (const character of valueArg) {
17
+ const codePoint = character.codePointAt(0);
18
+ switch (character) {
19
+ case '"':
20
+ result += '&#34;';
21
+ break;
22
+ case "'":
23
+ result += '&#39;';
24
+ break;
25
+ case '&':
26
+ result += '&amp;';
27
+ break;
28
+ case '<':
29
+ result += '&lt;';
30
+ break;
31
+ case '>':
32
+ result += '&gt;';
33
+ break;
34
+ case '\t':
35
+ result += '&#x9;';
36
+ break;
37
+ case '\n':
38
+ result += '&#xA;';
39
+ break;
40
+ case '\r':
41
+ result += '&#xD;';
42
+ break;
43
+ default:
44
+ result += isXmlCharacter(codePoint) ? character : '\ufffd';
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+ /** Go's `isInCharacterRange`. */
50
+ function isXmlCharacter(codePointArg) {
51
+ return (codePointArg === 0x09 ||
52
+ codePointArg === 0x0a ||
53
+ codePointArg === 0x0d ||
54
+ (codePointArg >= 0x20 && codePointArg <= 0xd7ff) ||
55
+ (codePointArg >= 0xe000 && codePointArg <= 0xfffd) ||
56
+ (codePointArg >= 0x10000 && codePointArg <= 0x10ffff));
57
+ }
58
+ /** `<name attr="…">content</name>`, where `contentArg` is already XML. */
59
+ export function element(nameArg, attributesArg, contentArg = '') {
60
+ let start = `<${nameArg}`;
61
+ for (const [attribute, value] of attributesArg) {
62
+ if (value !== undefined) {
63
+ start += ` ${attribute}="${escapeXml(String(value))}"`;
64
+ }
65
+ }
66
+ return `${start}>${contentArg}</${nameArg}>`;
67
+ }
68
+ /** `<name>escaped text</name>`. */
69
+ export function textElement(nameArg, textArg, attributesArg = []) {
70
+ return element(nameArg, attributesArg, escapeXml(textArg));
71
+ }
72
+ /** Go's `strings.Compare`: UTF-8 byte order, which is code point order. */
73
+ export function compareCodePoints(aArg, bArg) {
74
+ const length = Math.min(aArg.length, bArg.length);
75
+ for (let i = 0; i < length; i++) {
76
+ const a = aArg.charCodeAt(i);
77
+ const b = bArg.charCodeAt(i);
78
+ if (a !== b) {
79
+ // a surrogate (an astral code point) sorts after every other BMP unit
80
+ const aSurrogate = a >= 0xd800 && a <= 0xdfff;
81
+ const bSurrogate = b >= 0xd800 && b <= 0xdfff;
82
+ if (aSurrogate !== bSurrogate) {
83
+ return aSurrogate ? 1 : -1;
84
+ }
85
+ return a < b ? -1 : 1;
86
+ }
87
+ }
88
+ return aArg.length === bArg.length ? 0 : aArg.length < bArg.length ? -1 : 1;
89
+ }
90
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieG1sLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcnBtL3htbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxNQUFNLENBQUMsTUFBTSxVQUFVLEdBQUcsMENBQTBDLENBQUM7QUFFckUsTUFBTSxZQUFZLEdBQUcsK0NBQStDLENBQUM7QUFFckUsNERBQTREO0FBQzVELE1BQU0sVUFBVSxTQUFTLENBQUMsUUFBZ0I7SUFDeEMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUNqQyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQ0QsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ2hCLEtBQUssTUFBTSxTQUFTLElBQUksUUFBUSxFQUFFLENBQUM7UUFDakMsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUUsQ0FBQztRQUM1QyxRQUFRLFNBQVMsRUFBRSxDQUFDO1lBQ2xCLEtBQUssR0FBRztnQkFDTixNQUFNLElBQUksT0FBTyxDQUFDO2dCQUNsQixNQUFNO1lBQ1IsS0FBSyxHQUFHO2dCQUNOLE1BQU0sSUFBSSxPQUFPLENBQUM7Z0JBQ2xCLE1BQU07WUFDUixLQUFLLEdBQUc7Z0JBQ04sTUFBTSxJQUFJLE9BQU8sQ0FBQztnQkFDbEIsTUFBTTtZQUNSLEtBQUssR0FBRztnQkFDTixNQUFNLElBQUksTUFBTSxDQUFDO2dCQUNqQixNQUFNO1lBQ1IsS0FBSyxHQUFHO2dCQUNOLE1BQU0sSUFBSSxNQUFNLENBQUM7Z0JBQ2pCLE1BQU07WUFDUixLQUFLLElBQUk7Z0JBQ1AsTUFBTSxJQUFJLE9BQU8sQ0FBQztnQkFDbEIsTUFBTTtZQUNSLEtBQUssSUFBSTtnQkFDUCxNQUFNLElBQUksT0FBTyxDQUFDO2dCQUNsQixNQUFNO1lBQ1IsS0FBSyxJQUFJO2dCQUNQLE1BQU0sSUFBSSxPQUFPLENBQUM7Z0JBQ2xCLE1B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
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether an architecture can name an index path segment. Readers record any
3
+ * architecture a package states (Gitea accepts them); builders refuse an entry
4
+ * whose architecture fails this rule with `invalid-input`, and never skip it
5
+ * silently. Refused: the empty string, `.` and `..`, and any value containing
6
+ * `/`, whitespace or a control character.
7
+ */
8
+ export declare function isIndexableArchitecture(architectureArg: string): boolean;