@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.
- package/.smartconfig.json +64 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/alpine/apkindex.d.ts +39 -0
- package/dist_ts/alpine/apkindex.js +211 -0
- package/dist_ts/alpine/pkginfo.d.ts +45 -0
- package/dist_ts/alpine/pkginfo.js +159 -0
- package/dist_ts/alpine/reader.d.ts +20 -0
- package/dist_ts/alpine/reader.js +89 -0
- package/dist_ts/arch/builder.d.ts +41 -0
- package/dist_ts/arch/builder.js +234 -0
- package/dist_ts/arch/reader.d.ts +16 -0
- package/dist_ts/arch/reader.js +271 -0
- package/dist_ts/arch/signer.d.ts +21 -0
- package/dist_ts/arch/signer.js +66 -0
- package/dist_ts/arch/vercmp.d.ts +12 -0
- package/dist_ts/arch/vercmp.js +170 -0
- package/dist_ts/debian/control.d.ts +22 -0
- package/dist_ts/debian/control.js +137 -0
- package/dist_ts/debian/gostring.d.ts +26 -0
- package/dist_ts/debian/gostring.js +145 -0
- package/dist_ts/debian/indexbuilder.d.ts +47 -0
- package/dist_ts/debian/indexbuilder.js +299 -0
- package/dist_ts/debian/mailaddress.d.ts +12 -0
- package/dist_ts/debian/mailaddress.js +736 -0
- package/dist_ts/debian/reader.d.ts +30 -0
- package/dist_ts/debian/reader.js +110 -0
- package/dist_ts/index.d.ts +23 -0
- package/dist_ts/index.js +18 -0
- package/dist_ts/plugins.d.ts +8 -0
- package/dist_ts/plugins.js +11 -0
- package/dist_ts/readers/ar.d.ts +31 -0
- package/dist_ts/readers/ar.js +87 -0
- package/dist_ts/readers/bytes.d.ts +58 -0
- package/dist_ts/readers/bytes.js +147 -0
- package/dist_ts/readers/bytesource.d.ts +40 -0
- package/dist_ts/readers/bytesource.js +154 -0
- package/dist_ts/readers/decompress.d.ts +43 -0
- package/dist_ts/readers/decompress.js +269 -0
- package/dist_ts/readers/gzipmember.d.ts +32 -0
- package/dist_ts/readers/gzipmember.js +176 -0
- package/dist_ts/readers/tar.d.ts +85 -0
- package/dist_ts/readers/tar.js +731 -0
- package/dist_ts/readers/text.d.ts +16 -0
- package/dist_ts/readers/text.js +96 -0
- package/dist_ts/rpm/builder.d.ts +28 -0
- package/dist_ts/rpm/builder.js +208 -0
- package/dist_ts/rpm/header.d.ts +138 -0
- package/dist_ts/rpm/header.js +546 -0
- package/dist_ts/rpm/reader.d.ts +20 -0
- package/dist_ts/rpm/reader.js +306 -0
- package/dist_ts/rpm/repoconfig.d.ts +15 -0
- package/dist_ts/rpm/repoconfig.js +38 -0
- package/dist_ts/rpm/repodata.d.ts +44 -0
- package/dist_ts/rpm/repodata.js +148 -0
- package/dist_ts/rpm/sign.d.ts +30 -0
- package/dist_ts/rpm/sign.js +183 -0
- package/dist_ts/rpm/updates.d.ts +38 -0
- package/dist_ts/rpm/updates.js +265 -0
- package/dist_ts/rpm/xml.d.ts +18 -0
- package/dist_ts/rpm/xml.js +90 -0
- package/dist_ts/shared/architecture.d.ts +8 -0
- package/dist_ts/shared/architecture.js +17 -0
- package/dist_ts/shared/errors.d.ts +38 -0
- package/dist_ts/shared/errors.js +22 -0
- package/dist_ts/shared/gopath.d.ts +13 -0
- package/dist_ts/shared/gopath.js +53 -0
- package/dist_ts/shared/gostrings.d.ts +14 -0
- package/dist_ts/shared/gostrings.js +29 -0
- package/dist_ts/shared/limits.d.ts +47 -0
- package/dist_ts/shared/limits.js +57 -0
- package/dist_ts/shared/types.d.ts +213 -0
- package/dist_ts/shared/types.js +13 -0
- package/dist_ts/shared/url.d.ts +18 -0
- package/dist_ts/shared/url.js +371 -0
- package/dist_ts/shared/validation.d.ts +21 -0
- package/dist_ts/shared/validation.js +58 -0
- package/dist_ts/signing/keys.d.ts +36 -0
- package/dist_ts/signing/keys.js +89 -0
- package/dist_ts/signing/openpgpframing.d.ts +33 -0
- package/dist_ts/signing/openpgpframing.js +93 -0
- package/dist_ts/signing/signers.d.ts +63 -0
- package/dist_ts/signing/signers.js +248 -0
- package/dist_ts/writers/gotar.d.ts +43 -0
- package/dist_ts/writers/gotar.js +218 -0
- package/license.md +19 -0
- package/package.json +56 -3
- package/readme.md +176 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/alpine/apkindex.ts +241 -0
- package/ts/alpine/pkginfo.ts +183 -0
- package/ts/alpine/reader.ts +96 -0
- package/ts/arch/builder.ts +283 -0
- package/ts/arch/reader.ts +307 -0
- package/ts/arch/signer.ts +70 -0
- package/ts/arch/vercmp.ts +188 -0
- package/ts/debian/control.ts +150 -0
- package/ts/debian/gostring.ts +150 -0
- package/ts/debian/indexbuilder.ts +355 -0
- package/ts/debian/mailaddress.ts +754 -0
- package/ts/debian/reader.ts +126 -0
- package/ts/index.ts +46 -0
- package/ts/plugins.ts +13 -0
- package/ts/readers/ar.ts +102 -0
- package/ts/readers/bytes.ts +182 -0
- package/ts/readers/bytesource.ts +164 -0
- package/ts/readers/decompress.ts +332 -0
- package/ts/readers/gzipmember.ts +209 -0
- package/ts/readers/tar.ts +835 -0
- package/ts/readers/text.ts +91 -0
- package/ts/rpm/builder.ts +253 -0
- package/ts/rpm/header.ts +628 -0
- package/ts/rpm/reader.ts +317 -0
- package/ts/rpm/repoconfig.ts +45 -0
- package/ts/rpm/repodata.ts +219 -0
- package/ts/rpm/sign.ts +200 -0
- package/ts/rpm/updates.ts +314 -0
- package/ts/rpm/xml.ts +101 -0
- package/ts/shared/architecture.ts +16 -0
- package/ts/shared/errors.ts +78 -0
- package/ts/shared/gopath.ts +54 -0
- package/ts/shared/gostrings.ts +31 -0
- package/ts/shared/limits.ts +93 -0
- package/ts/shared/types.ts +251 -0
- package/ts/shared/url.ts +387 -0
- package/ts/shared/validation.ts +71 -0
- package/ts/signing/keys.ts +110 -0
- package/ts/signing/openpgpframing.ts +115 -0
- package/ts/signing/signers.ts +315 -0
- package/ts/writers/gotar.ts +256 -0
- package/README.md +0 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { LinuxRepoError } from '../shared/errors.js';
|
|
2
|
+
import { assertAsyncIterable, assertBytes, assertString, assertTimestamp } from '../shared/validation.js';
|
|
3
|
+
import { singleChunk } from './signers.js';
|
|
4
|
+
/**
|
|
5
|
+
* The OpenPGP framing the codec owns: only the bytes of the signature packet
|
|
6
|
+
* may vary; framing and armor are deterministic.
|
|
7
|
+
* Armor has no headers, 64-column base64 and a CRC-24 line.
|
|
8
|
+
*/
|
|
9
|
+
const BASE64_LINE = 64;
|
|
10
|
+
/**
|
|
11
|
+
* Signs the concatenation of the chunks of `data` and returns the signer's
|
|
12
|
+
* binary packet unchanged (Arch `.sig`, RPM header tags). The signer reads
|
|
13
|
+
* `data` to its end exactly once.
|
|
14
|
+
*/
|
|
15
|
+
export async function createDetachedBinarySignature(inputArg) {
|
|
16
|
+
assertAsyncIterable(inputArg.data, 'data');
|
|
17
|
+
assertTimestamp(inputArg.timestamp);
|
|
18
|
+
const packet = await inputArg.signer.signBinary(inputArg.data, inputArg.timestamp);
|
|
19
|
+
assertSignatureBytes(packet);
|
|
20
|
+
return packet;
|
|
21
|
+
}
|
|
22
|
+
/** Signs `data` and returns an armored detached signature (`Release.gpg`, `repomd.xml.asc`). */
|
|
23
|
+
export async function createDetachedArmoredSignature(inputArg) {
|
|
24
|
+
assertBytes(inputArg.data, 'data');
|
|
25
|
+
return armorSignature(await createDetachedBinarySignature({
|
|
26
|
+
data: singleChunk(inputArg.data),
|
|
27
|
+
signer: inputArg.signer,
|
|
28
|
+
timestamp: inputArg.timestamp,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Cleartext-signs `text` (`InRelease`). The text must be canonical: no CR and
|
|
33
|
+
* no trailing spaces or tabs on any line. The signed text is `text` without
|
|
34
|
+
* its final line break; the output always ends the text with one line break
|
|
35
|
+
* before the signature block, as GnuPG and Go do. Lines starting with `-` are
|
|
36
|
+
* dash-escaped. The header is always `Hash: SHA256`.
|
|
37
|
+
*/
|
|
38
|
+
export async function createCleartextSignedMessage(inputArg) {
|
|
39
|
+
assertCanonicalText(inputArg.text);
|
|
40
|
+
assertTimestamp(inputArg.timestamp);
|
|
41
|
+
const signedText = inputArg.text.endsWith('\n') ? inputArg.text.slice(0, -1) : inputArg.text;
|
|
42
|
+
const packet = await inputArg.signer.signText(signedText, inputArg.timestamp);
|
|
43
|
+
assertSignatureBytes(packet);
|
|
44
|
+
const body = `${signedText}\n`.replace(/^-/gm, '- -');
|
|
45
|
+
return `-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n${body}${armorSignature(packet)}`;
|
|
46
|
+
}
|
|
47
|
+
/** ASCII armor for one signature packet list. */
|
|
48
|
+
export function armorSignature(packetArg) {
|
|
49
|
+
const base64 = Buffer.from(packetArg.buffer, packetArg.byteOffset, packetArg.byteLength).toString('base64');
|
|
50
|
+
const lines = [];
|
|
51
|
+
for (let offset = 0; offset < base64.length; offset += BASE64_LINE) {
|
|
52
|
+
lines.push(base64.slice(offset, offset + BASE64_LINE));
|
|
53
|
+
}
|
|
54
|
+
return [
|
|
55
|
+
'-----BEGIN PGP SIGNATURE-----',
|
|
56
|
+
'',
|
|
57
|
+
...lines,
|
|
58
|
+
`=${crc24Base64(packetArg)}`,
|
|
59
|
+
'-----END PGP SIGNATURE-----',
|
|
60
|
+
'',
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|
|
63
|
+
/** Refuses text that is not canonical cleartext input. */
|
|
64
|
+
export function assertCanonicalText(textArg) {
|
|
65
|
+
assertString(textArg, 'text');
|
|
66
|
+
if (textArg.includes('\r')) {
|
|
67
|
+
throw new LinuxRepoError('invalid-input', 'cleartext must use LF line endings', { field: 'text' });
|
|
68
|
+
}
|
|
69
|
+
if (/[ \t]$/m.test(textArg)) {
|
|
70
|
+
throw new LinuxRepoError('invalid-input', 'cleartext lines must not end with spaces or tabs', { field: 'text' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function assertSignatureBytes(packetArg) {
|
|
74
|
+
if (!(packetArg instanceof Uint8Array) || packetArg.length === 0) {
|
|
75
|
+
throw new LinuxRepoError('signing-failed', 'the signer returned no signature bytes', { field: 'signer' });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** RFC 4880 section 6.1 CRC-24, base64-encoded. */
|
|
79
|
+
function crc24Base64(bytesArg) {
|
|
80
|
+
let crc = 0xb704ce;
|
|
81
|
+
for (let i = 0; i < bytesArg.length; i++) {
|
|
82
|
+
crc ^= bytesArg[i] << 16;
|
|
83
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
84
|
+
crc <<= 1;
|
|
85
|
+
if (crc & 0x1000000) {
|
|
86
|
+
crc ^= 0x1864cfb;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
crc &= 0xffffff;
|
|
91
|
+
return Buffer.from([(crc >> 16) & 0xff, (crc >> 8) & 0xff, crc & 0xff]).toString('base64');
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbnBncGZyYW1pbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9zaWduaW5nL29wZW5wZ3BmcmFtaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRyxPQUFPLEVBQUUsV0FBVyxFQUF1QixNQUFNLGNBQWMsQ0FBQztBQUVoRTs7OztHQUlHO0FBRUgsTUFBTSxXQUFXLEdBQUcsRUFBRSxDQUFDO0FBRXZCOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLDZCQUE2QixDQUFDLFFBSW5EO0lBQ0MsbUJBQW1CLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUMzQyxlQUFlLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3BDLE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkYsb0JBQW9CLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDN0IsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVELGdHQUFnRztBQUNoRyxNQUFNLENBQUMsS0FBSyxVQUFVLDhCQUE4QixDQUFDLFFBSXBEO0lBQ0MsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDbkMsT0FBTyxjQUFjLENBQ25CLE1BQU0sNkJBQTZCLENBQUM7UUFDbEMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ2hDLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTTtRQUN2QixTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVM7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
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signs Alpine indexes. Consumers may implement it; adding a required member
|
|
3
|
+
* later needs a major release.
|
|
4
|
+
*/
|
|
5
|
+
export interface IAlpineSigner {
|
|
6
|
+
/**
|
|
7
|
+
* The key name apk looks up in `/etc/apk/keys`; the index signature entry is
|
|
8
|
+
* `.SIGN.RSA.<keyName>`. Gitea's form is `<owner>@<sha256 hex of the SPKI
|
|
9
|
+
* DER public key>.rsa.pub` (see `giteaAlpineKeyName`).
|
|
10
|
+
*/
|
|
11
|
+
readonly keyName: string;
|
|
12
|
+
/** RSASSA-PKCS1-v1_5 over SHA-1 of `data`; returns the raw signature bytes. */
|
|
13
|
+
sign(data: Uint8Array): Promise<Uint8Array>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Signs Debian, RPM and Arch documents. Consumers may implement it; adding a
|
|
17
|
+
* required member later needs a major release.
|
|
18
|
+
*
|
|
19
|
+
* Contract: each call returns exactly one binary OpenPGP v4 signature packet
|
|
20
|
+
* (packet header included, no armor), hashed with SHA-256, whose creation time
|
|
21
|
+
* is `timestamp` (whole seconds). The codec does all framing (armor, cleartext
|
|
22
|
+
* dash-escaping, the `Hash: SHA256` header) and treats the packet as opaque.
|
|
23
|
+
*/
|
|
24
|
+
export interface IOpenPgpSigner {
|
|
25
|
+
/**
|
|
26
|
+
* A signature of type 0x00 (binary document) over the concatenation of the
|
|
27
|
+
* chunks of `data`. The signer reads `data` to its end exactly once.
|
|
28
|
+
*/
|
|
29
|
+
signBinary(data: AsyncIterable<Uint8Array>, timestamp: Date): Promise<Uint8Array>;
|
|
30
|
+
/**
|
|
31
|
+
* A signature of type 0x01 (canonical text document) over `text`. The codec
|
|
32
|
+
* passes canonical text only: LF line endings and no trailing spaces or tabs
|
|
33
|
+
* on any line; the signature hashes it with CRLF line endings.
|
|
34
|
+
*/
|
|
35
|
+
signText(text: string, timestamp: Date): Promise<Uint8Array>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds an Alpine signer from an unencrypted RSA private key in PEM form:
|
|
39
|
+
* PKCS#1 (`RSA PRIVATE KEY`, Gitea's stored form) or PKCS#8 (`PRIVATE KEY`).
|
|
40
|
+
* Anything else is `invalid-key`. Signatures are deterministic.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createAlpineSigner(inputArg: {
|
|
43
|
+
privateKeyPem: string;
|
|
44
|
+
keyName: string;
|
|
45
|
+
}): IAlpineSigner;
|
|
46
|
+
/**
|
|
47
|
+
* Builds an OpenPGP signer from an armored private key: exactly one key,
|
|
48
|
+
* OpenPGP v4, not encrypted, able to sign. Anything else is `invalid-key`.
|
|
49
|
+
* Signatures are SHA-256 and keep openpgp.js's salt notation, so their bytes
|
|
50
|
+
* vary per call; the produced packet is checked against the signer contract.
|
|
51
|
+
*
|
|
52
|
+
* The factory makes one trial `signBinary` and refuses the key with
|
|
53
|
+
* `invalid-key` when it fails, so a key that cannot meet the contract at all
|
|
54
|
+
* (one whose curve makes openpgp.js choose a stronger hash than SHA-256) is
|
|
55
|
+
* refused here. The trial signs at the latest creation time of the key, its
|
|
56
|
+
* subkeys and their self-signatures; a failure that depends on the signing
|
|
57
|
+
* time stays `signing-failed` at signing time.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createOpenPgpSigner(inputArg: {
|
|
60
|
+
privateKeyArmored: string;
|
|
61
|
+
}): Promise<IOpenPgpSigner>;
|
|
62
|
+
/** `bytesArg` as a one-chunk source, for callers that hold the whole document. */
|
|
63
|
+
export declare function singleChunk(bytesArg: Uint8Array): AsyncGenerator<Uint8Array>;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { concatBytes } from '../readers/bytes.js';
|
|
3
|
+
import { LinuxRepoError } from '../shared/errors.js';
|
|
4
|
+
import { assertAsyncIterable, assertBytes, assertSegmentName, assertString, assertTimestamp, } from '../shared/validation.js';
|
|
5
|
+
const ALPINE_PRIVATE_KEY_LABELS = ['RSA PRIVATE KEY', 'PRIVATE KEY'];
|
|
6
|
+
/**
|
|
7
|
+
* Builds an Alpine signer from an unencrypted RSA private key in PEM form:
|
|
8
|
+
* PKCS#1 (`RSA PRIVATE KEY`, Gitea's stored form) or PKCS#8 (`PRIVATE KEY`).
|
|
9
|
+
* Anything else is `invalid-key`. Signatures are deterministic.
|
|
10
|
+
*/
|
|
11
|
+
export function createAlpineSigner(inputArg) {
|
|
12
|
+
if (inputArg === null || typeof inputArg !== 'object') {
|
|
13
|
+
throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
|
|
14
|
+
}
|
|
15
|
+
assertString(inputArg.privateKeyPem, 'privateKeyPem');
|
|
16
|
+
assertSegmentName(inputArg.keyName, 'keyName');
|
|
17
|
+
const label = /-----BEGIN ([A-Z0-9 ]+)-----/.exec(inputArg.privateKeyPem)?.[1];
|
|
18
|
+
if (label === undefined || !ALPINE_PRIVATE_KEY_LABELS.includes(label)) {
|
|
19
|
+
throw new LinuxRepoError('invalid-key', 'the Alpine key must be an unencrypted PKCS#1 or PKCS#8 RSA private key PEM', {
|
|
20
|
+
field: 'privateKeyPem',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
let key;
|
|
24
|
+
try {
|
|
25
|
+
key = plugins.crypto.createPrivateKey({ key: inputArg.privateKeyPem, format: 'pem' });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new LinuxRepoError('invalid-key', 'the Alpine private key cannot be read', { field: 'privateKeyPem' }, {
|
|
29
|
+
cause: error,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (key.asymmetricKeyType !== 'rsa') {
|
|
33
|
+
throw new LinuxRepoError('invalid-key', 'the Alpine key must be an RSA key', { field: 'privateKeyPem' });
|
|
34
|
+
}
|
|
35
|
+
const keyName = inputArg.keyName;
|
|
36
|
+
return {
|
|
37
|
+
keyName,
|
|
38
|
+
sign: async (data) => {
|
|
39
|
+
assertBytes(data, 'data');
|
|
40
|
+
try {
|
|
41
|
+
const signature = plugins.crypto.sign('sha1', data, {
|
|
42
|
+
key,
|
|
43
|
+
padding: plugins.crypto.constants.RSA_PKCS1_PADDING,
|
|
44
|
+
});
|
|
45
|
+
return new Uint8Array(signature.buffer, signature.byteOffset, signature.byteLength);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new LinuxRepoError('signing-failed', 'RSA PKCS#1 v1.5 SHA-1 signing failed', { field: 'keyName' }, {
|
|
49
|
+
cause: error,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Builds an OpenPGP signer from an armored private key: exactly one key,
|
|
57
|
+
* OpenPGP v4, not encrypted, able to sign. Anything else is `invalid-key`.
|
|
58
|
+
* Signatures are SHA-256 and keep openpgp.js's salt notation, so their bytes
|
|
59
|
+
* vary per call; the produced packet is checked against the signer contract.
|
|
60
|
+
*
|
|
61
|
+
* The factory makes one trial `signBinary` and refuses the key with
|
|
62
|
+
* `invalid-key` when it fails, so a key that cannot meet the contract at all
|
|
63
|
+
* (one whose curve makes openpgp.js choose a stronger hash than SHA-256) is
|
|
64
|
+
* refused here. The trial signs at the latest creation time of the key, its
|
|
65
|
+
* subkeys and their self-signatures; a failure that depends on the signing
|
|
66
|
+
* time stays `signing-failed` at signing time.
|
|
67
|
+
*/
|
|
68
|
+
export async function createOpenPgpSigner(inputArg) {
|
|
69
|
+
if (inputArg === null || typeof inputArg !== 'object') {
|
|
70
|
+
throw new LinuxRepoError('invalid-input', 'input must be an object', { field: 'input' });
|
|
71
|
+
}
|
|
72
|
+
assertString(inputArg.privateKeyArmored, 'privateKeyArmored');
|
|
73
|
+
// openpgp.js reads the first armor block and ignores anything after it
|
|
74
|
+
const armorBlocks = inputArg.privateKeyArmored.match(/^-----BEGIN PGP [A-Z ,/0-9]+-----\s*$/gm) ?? [];
|
|
75
|
+
if (armorBlocks.length > 1) {
|
|
76
|
+
throw new LinuxRepoError('invalid-key', `expected one armored OpenPGP private key block, got ${armorBlocks.length}`, {
|
|
77
|
+
field: 'privateKeyArmored',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
let keys;
|
|
81
|
+
try {
|
|
82
|
+
keys = await plugins.openpgp.readPrivateKeys({ armoredKeys: inputArg.privateKeyArmored });
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw new LinuxRepoError('invalid-key', 'the OpenPGP private key cannot be read', { field: 'privateKeyArmored' }, {
|
|
86
|
+
cause: error,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (keys.length !== 1) {
|
|
90
|
+
throw new LinuxRepoError('invalid-key', `expected exactly one OpenPGP private key, got ${keys.length}`, {
|
|
91
|
+
field: 'privateKeyArmored',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const key = keys[0];
|
|
95
|
+
if (key.keyPacket.version !== 4) {
|
|
96
|
+
throw new LinuxRepoError('invalid-key', `only OpenPGP v4 keys are accepted, got v${key.keyPacket.version}`, {
|
|
97
|
+
field: 'privateKeyArmored',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (!key.isDecrypted()) {
|
|
101
|
+
throw new LinuxRepoError('invalid-key', 'encrypted OpenPGP keys are not accepted', { field: 'privateKeyArmored' });
|
|
102
|
+
}
|
|
103
|
+
const sign = async (produceArg, timestampArg, signatureTypeArg, inputFailureArg = () => undefined) => {
|
|
104
|
+
let packet;
|
|
105
|
+
try {
|
|
106
|
+
packet = await produceArg();
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// an invalid chunk or the caller's own source error, not a signing failure
|
|
110
|
+
const inputFailure = inputFailureArg();
|
|
111
|
+
if (inputFailure !== undefined) {
|
|
112
|
+
throw inputFailure.error;
|
|
113
|
+
}
|
|
114
|
+
throw new LinuxRepoError('signing-failed', 'OpenPGP signing failed', { field: 'signingKey' }, { cause: error });
|
|
115
|
+
}
|
|
116
|
+
await assertSignaturePacket(packet, timestampArg, signatureTypeArg);
|
|
117
|
+
return packet;
|
|
118
|
+
};
|
|
119
|
+
const config = { preferredHashAlgorithm: plugins.openpgp.enums.hash.sha256 };
|
|
120
|
+
const signer = {
|
|
121
|
+
signBinary: async (data, timestamp) => {
|
|
122
|
+
assertAsyncIterable(data, 'data');
|
|
123
|
+
assertTimestamp(timestamp);
|
|
124
|
+
const source = new CheckedChunkSource(data);
|
|
125
|
+
return sign(async () => {
|
|
126
|
+
const signature = await plugins.openpgp.sign({
|
|
127
|
+
message: await plugins.openpgp.createMessage({ binary: source.toReadableStream() }),
|
|
128
|
+
signingKeys: key,
|
|
129
|
+
detached: true,
|
|
130
|
+
format: 'binary',
|
|
131
|
+
date: timestamp,
|
|
132
|
+
config,
|
|
133
|
+
});
|
|
134
|
+
const packet = await readAll(signature);
|
|
135
|
+
if (!source.ended) {
|
|
136
|
+
throw new Error('openpgp.js returned a signature before reading the data to its end');
|
|
137
|
+
}
|
|
138
|
+
return packet;
|
|
139
|
+
}, timestamp, plugins.openpgp.enums.signature.binary, () => source.failure);
|
|
140
|
+
},
|
|
141
|
+
signText: async (text, timestamp) => {
|
|
142
|
+
assertString(text, 'text');
|
|
143
|
+
assertTimestamp(timestamp);
|
|
144
|
+
return sign(async () => plugins.openpgp.sign({
|
|
145
|
+
message: await plugins.openpgp.createMessage({ text }),
|
|
146
|
+
signingKeys: key,
|
|
147
|
+
detached: true,
|
|
148
|
+
format: 'binary',
|
|
149
|
+
date: timestamp,
|
|
150
|
+
config,
|
|
151
|
+
}), timestamp, plugins.openpgp.enums.signature.text);
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
try {
|
|
155
|
+
await signer.signBinary(singleChunk(new Uint8Array(0)), latestKeyTime(key));
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
throw new LinuxRepoError('invalid-key', 'the OpenPGP key cannot sign a v4 SHA-256 signature', { field: 'privateKeyArmored' }, {
|
|
159
|
+
cause: error,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return signer;
|
|
163
|
+
}
|
|
164
|
+
/** `bytesArg` as a one-chunk source, for callers that hold the whole document. */
|
|
165
|
+
export async function* singleChunk(bytesArg) {
|
|
166
|
+
yield bytesArg;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Pulls the caller's source with `next()` only (never `return()` or
|
|
170
|
+
* `throw()`, so a cancelled stream never cancels the source), refuses a chunk
|
|
171
|
+
* that is not a `Uint8Array` with `invalid-input`, and records the first
|
|
172
|
+
* error it raised or met so the signer can rethrow it unchanged.
|
|
173
|
+
*/
|
|
174
|
+
class CheckedChunkSource {
|
|
175
|
+
ended = false;
|
|
176
|
+
failure = undefined;
|
|
177
|
+
source;
|
|
178
|
+
constructor(sourceArg) {
|
|
179
|
+
this.source = sourceArg;
|
|
180
|
+
}
|
|
181
|
+
toReadableStream() {
|
|
182
|
+
const iterator = this.source[Symbol.asyncIterator]();
|
|
183
|
+
const next = async () => {
|
|
184
|
+
let result;
|
|
185
|
+
try {
|
|
186
|
+
result = await iterator.next();
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
this.failure ??= { error };
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
if (result.done === true) {
|
|
193
|
+
this.ended = true;
|
|
194
|
+
return { done: true, value: undefined };
|
|
195
|
+
}
|
|
196
|
+
if (!(result.value instanceof Uint8Array)) {
|
|
197
|
+
const error = new LinuxRepoError('invalid-input', 'every chunk of data must be a Uint8Array', { field: 'data' });
|
|
198
|
+
this.failure ??= { error };
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
return { done: false, value: result.value };
|
|
202
|
+
};
|
|
203
|
+
return plugins.streamWeb.ReadableStream.from({ [Symbol.asyncIterator]: () => ({ next }) });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/** Reads openpgp.js's streamed output to its end. */
|
|
207
|
+
async function readAll(streamArg) {
|
|
208
|
+
const reader = streamArg.getReader();
|
|
209
|
+
const chunks = [];
|
|
210
|
+
let total = 0;
|
|
211
|
+
for (let result = await reader.read(); !result.done; result = await reader.read()) {
|
|
212
|
+
chunks.push(result.value);
|
|
213
|
+
total += result.value.length;
|
|
214
|
+
}
|
|
215
|
+
return concatBytes(chunks, total);
|
|
216
|
+
}
|
|
217
|
+
/** The latest creation time of the key, its subkeys and their self-signatures: the key's current state applies. */
|
|
218
|
+
function latestKeyTime(keyArg) {
|
|
219
|
+
const times = [keyArg.getCreationTime().getTime()];
|
|
220
|
+
for (const user of keyArg.users) {
|
|
221
|
+
for (const signature of user.selfCertifications) {
|
|
222
|
+
times.push(signature.created?.getTime() ?? 0);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const subkey of keyArg.subkeys) {
|
|
226
|
+
times.push(subkey.getCreationTime().getTime());
|
|
227
|
+
for (const signature of subkey.bindingSignatures) {
|
|
228
|
+
times.push(signature.created?.getTime() ?? 0);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return new Date(Math.max(...times));
|
|
232
|
+
}
|
|
233
|
+
/** Checks that openpgp.js produced exactly the packet the signer contract promises. */
|
|
234
|
+
async function assertSignaturePacket(packetArg, timestampArg, signatureTypeArg) {
|
|
235
|
+
const signature = await plugins.openpgp.readSignature({ binarySignature: packetArg });
|
|
236
|
+
const packets = signature.packets;
|
|
237
|
+
const expectedSeconds = Math.floor(timestampArg.getTime() / 1000);
|
|
238
|
+
const ok = packets.length === 1 &&
|
|
239
|
+
packets[0].version === 4 &&
|
|
240
|
+
packets[0].signatureType === signatureTypeArg &&
|
|
241
|
+
packets[0].hashAlgorithm === plugins.openpgp.enums.hash.sha256 &&
|
|
242
|
+
packets[0].created !== null &&
|
|
243
|
+
Math.floor(packets[0].created.getTime() / 1000) === expectedSeconds;
|
|
244
|
+
if (!ok) {
|
|
245
|
+
throw new LinuxRepoError('signing-failed', 'the signing key cannot produce one v4 SHA-256 signature packet at the requested time', { field: 'signingKey' });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbmVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3NpZ25pbmcvc2lnbmVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsV0FBVyxFQUNYLGlCQUFpQixFQUNqQixZQUFZLEVBQ1osZUFBZSxHQUNoQixNQUFNLHlCQUF5QixDQUFDO0FBd0NqQyxNQUFNLHlCQUF5QixHQUFHLENBQUMsaUJBQWlCLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFFckU7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxRQUFvRDtJQUNyRixJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDdEQsTUFBTSxJQUFJLGNBQWMsQ0FBQyxlQUFlLEVBQUUseUJBQXlCLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBQ0QsWUFBWSxDQUFDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDdEQsaUJBQWlCLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztJQUMvQyxNQUFNLEtBQUssR0FBRyw4QkFBOEIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0UsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLENBQUMseUJBQXlCLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDdEUsTUFBTSxJQUFJLGNBQWMsQ0FBQyxhQUFhLEVBQUUsNEVBQTRFLEVBQUU7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
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface IGoTarFile {
|
|
2
|
+
name: string;
|
|
3
|
+
mode: number;
|
|
4
|
+
data: Uint8Array;
|
|
5
|
+
}
|
|
6
|
+
export interface IGoTarWriteOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The two zero blocks Go `Writer.Close` writes. `false` for Gitea's Alpine
|
|
9
|
+
* signature member (`writeGzipStream` with `addTarEnd=false`). Gitea never
|
|
10
|
+
* calls `Close` there, so Go also leaves the last entry unpadded; the codec
|
|
11
|
+
* pads every entry to the block regardless (a difference from Gitea).
|
|
12
|
+
*/
|
|
13
|
+
endOfArchive: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The subset of Go 1.27 `archive/tar` `Writer` that Gitea 28.2.0 uses for its
|
|
17
|
+
* index archives (Arch `services/packages/arch/repository.go:381-399`, Alpine
|
|
18
|
+
* `services/packages/alpine/repository.go:331-351`): regular files from
|
|
19
|
+
* `tar.Header{Name, Mode, Size}` with every other field zero, so the zero
|
|
20
|
+
* `ModTime` is written as 0, uid and gid are 0 and user and group names are
|
|
21
|
+
* empty.
|
|
22
|
+
*
|
|
23
|
+
* Format choice follows Go's `allowedFormats` and `WriteHeader`: USTAR when the
|
|
24
|
+
* name is ASCII and at most 100 bytes, USTAR with a prefix split when the name
|
|
25
|
+
* splits, else PAX with one `path` record (refused when the records exceed
|
|
26
|
+
* Go's 1 MiB `maxSpecialFileSize`, as Go returns `ErrFieldTooLong`).
|
|
27
|
+
*
|
|
28
|
+
* Refused with `invalid-input` where Go would not write a regular file in USTAR
|
|
29
|
+
* or PAX-`path` form:
|
|
30
|
+
* - a name with NUL (Go fails with an invalid PAX record) or ending with `/`
|
|
31
|
+
* (Go refuses it for a regular file; Gitea's untyped header would become a
|
|
32
|
+
* directory entry instead);
|
|
33
|
+
* - a mode outside 7 octal digits (Go falls back to the GNU format);
|
|
34
|
+
* - a size of 8 GiB or more (Go adds a PAX `size` record; the codec does not);
|
|
35
|
+
* - a string that is not well-formed UTF-16 (Go strings never carry one).
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeGoTar(filesArg: readonly IGoTarFile[], optionsArg?: IGoTarWriteOptions): Uint8Array;
|
|
38
|
+
/**
|
|
39
|
+
* The bytes Go `Writer.WriteHeader` writes for a regular file: the main
|
|
40
|
+
* header block, preceded by a PAX `x` header and its padded records when the
|
|
41
|
+
* name needs one.
|
|
42
|
+
*/
|
|
43
|
+
export declare function goTarHeader(nameArg: string, modeArg: number, sizeArg: number): Uint8Array;
|