@multiplatform.one/gpg 7.17.0 → 7.19.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 (59) hide show
  1. package/dist/cjs/GpgIcon.cjs +55 -0
  2. package/dist/cjs/GpgIcon.native.js +72 -0
  3. package/dist/cjs/GpgIcon.native.js.map +1 -0
  4. package/dist/cjs/GpgProvider.cjs +7 -4
  5. package/dist/cjs/GpgProvider.native.js +7 -4
  6. package/dist/cjs/GpgProvider.native.js.map +1 -1
  7. package/dist/cjs/index.cjs +7 -1
  8. package/dist/cjs/index.native.js +7 -1
  9. package/dist/cjs/index.native.js.map +1 -1
  10. package/dist/cjs/screens.cjs +9 -2
  11. package/dist/cjs/screens.native.js +15 -2
  12. package/dist/cjs/screens.native.js.map +1 -1
  13. package/dist/cjs/signature.cjs +113 -0
  14. package/dist/cjs/signature.native.js +124 -0
  15. package/dist/cjs/signature.native.js.map +1 -0
  16. package/dist/cjs/signer.cjs +119 -0
  17. package/dist/cjs/signer.native.js +150 -0
  18. package/dist/cjs/signer.native.js.map +1 -0
  19. package/dist/esm/GpgIcon.mjs +30 -0
  20. package/dist/esm/GpgIcon.mjs.map +1 -0
  21. package/dist/esm/GpgIcon.native.js +33 -0
  22. package/dist/esm/GpgIcon.native.js.map +1 -0
  23. package/dist/esm/GpgProvider.mjs +7 -4
  24. package/dist/esm/GpgProvider.mjs.map +1 -1
  25. package/dist/esm/GpgProvider.native.js +7 -4
  26. package/dist/esm/GpgProvider.native.js.map +1 -1
  27. package/dist/esm/index.mjs +2 -1
  28. package/dist/esm/index.mjs.map +1 -1
  29. package/dist/esm/index.native.js +2 -1
  30. package/dist/esm/index.native.js.map +1 -1
  31. package/dist/esm/screens.mjs +9 -2
  32. package/dist/esm/screens.mjs.map +1 -1
  33. package/dist/esm/screens.native.js +15 -2
  34. package/dist/esm/screens.native.js.map +1 -1
  35. package/dist/esm/signature.mjs +88 -0
  36. package/dist/esm/signature.mjs.map +1 -0
  37. package/dist/esm/signature.native.js +96 -0
  38. package/dist/esm/signature.native.js.map +1 -0
  39. package/dist/esm/signer.mjs +88 -0
  40. package/dist/esm/signer.mjs.map +1 -0
  41. package/dist/esm/signer.native.js +116 -0
  42. package/dist/esm/signer.native.js.map +1 -0
  43. package/package.json +16 -3
  44. package/src/GpgIcon.tsx +20 -0
  45. package/src/GpgProvider.tsx +7 -19
  46. package/src/index.ts +10 -1
  47. package/src/screens.tsx +11 -1
  48. package/src/signature.ts +120 -0
  49. package/src/signer.ts +142 -0
  50. package/types/GpgIcon.d.ts +3 -0
  51. package/types/GpgIcon.d.ts.map +1 -0
  52. package/types/GpgProvider.d.ts.map +1 -1
  53. package/types/index.d.ts +1 -0
  54. package/types/index.d.ts.map +1 -1
  55. package/types/screens.d.ts.map +1 -1
  56. package/types/signature.d.ts +6 -0
  57. package/types/signature.d.ts.map +1 -0
  58. package/types/signer.d.ts +47 -0
  59. package/types/signer.d.ts.map +1 -0
@@ -0,0 +1,88 @@
1
+ import { ripemd160, sha1 } from "@noble/hashes/legacy.js";
2
+ import { sha224, sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
3
+ const BEGIN = "-----BEGIN PGP SIGNATURE-----";
4
+ const END = "-----END PGP SIGNATURE-----";
5
+ const hashes = {
6
+ 2: sha1,
7
+ 3: ripemd160,
8
+ 8: sha256,
9
+ 9: sha384,
10
+ 10: sha512,
11
+ 11: sha224
12
+ };
13
+ function dearmor(text) {
14
+ const start = text.indexOf(BEGIN);
15
+ const end = text.indexOf(END, start);
16
+ if (start < 0 || end < 0) throw new Error("No PGP SIGNATURE block in the paste");
17
+ const lines = text.slice(start + BEGIN.length, end).split(/\r?\n/).map(line => line.trim());
18
+ const blank = lines.indexOf("", 1);
19
+ const hasHeaders = lines.slice(1, blank < 0 ? 0 : blank).some(line => line.includes(": "));
20
+ const body = (hasHeaders ? lines.slice(blank) : lines).filter(line => line && !/^=[A-Za-z0-9+/]{4}$/.test(line));
21
+ const binary = atob(body.join(""));
22
+ return Uint8Array.from(binary, c => c.charCodeAt(0));
23
+ }
24
+ function signaturePackets(bytes) {
25
+ const packets = [];
26
+ let at = 0;
27
+ while (at < bytes.length) {
28
+ const ctb = bytes[at++];
29
+ if (!(ctb & 128)) throw new Error("The PGP SIGNATURE block is not OpenPGP data");
30
+ let tag;
31
+ let length;
32
+ if (ctb & 64) {
33
+ tag = ctb & 63;
34
+ const first = bytes[at++];
35
+ if (first < 192) length = first;else if (first < 224) length = (first - 192 << 8) + bytes[at++] + 192;else if (first === 255) {
36
+ length = new DataView(bytes.buffer, bytes.byteOffset + at, 4).getUint32(0);
37
+ at += 4;
38
+ } else throw new Error("Partial-length PGP packets are not a detached signature");
39
+ } else {
40
+ tag = ctb >> 2 & 15;
41
+ const size = [1, 2, 4][ctb & 3];
42
+ if (size === void 0) throw new Error("Indeterminate-length PGP packets are not supported");
43
+ length = 0;
44
+ for (let i = 0; i < size; i++) length = length * 256 + bytes[at++];
45
+ }
46
+ if (at + length > bytes.length) throw new Error("The PGP SIGNATURE block is truncated");
47
+ if (tag === 2) packets.push(bytes.subarray(at, at + length));
48
+ at += length;
49
+ }
50
+ return packets;
51
+ }
52
+ function quickCheck(packet, message) {
53
+ if (packet[0] !== 4) {
54
+ throw new Error(`A version ${packet[0]} PGP signature cannot be checked here; sign with a v4 key`);
55
+ }
56
+ const sigType = packet[1];
57
+ if (sigType !== 0 && sigType !== 1) {
58
+ throw new Error(`PGP signature type 0x${sigType.toString(16)} is not a document signature`);
59
+ }
60
+ const hash = hashes[packet[3]];
61
+ if (!hash) throw new Error(`PGP hash algorithm ${packet[3]} is not supported`);
62
+ const hashedEnd = 6 + (packet[4] << 8 | packet[5]);
63
+ const unhashedLength = packet[hashedEnd] << 8 | packet[hashedEnd + 1];
64
+ const left16 = hashedEnd + 2 + unhashedLength;
65
+ if (left16 + 2 > packet.length) throw new Error("The PGP signature packet is truncated");
66
+ const data = sigType === 1 ? new TextEncoder().encode(new TextDecoder().decode(message).replace(/\r?\n/g, "\n").replace(/\n/g, "\r\n")) : message;
67
+ const trailer = new Uint8Array(6);
68
+ trailer[0] = 4;
69
+ trailer[1] = 255;
70
+ new DataView(trailer.buffer).setUint32(2, hashedEnd);
71
+ const input = new Uint8Array(data.length + hashedEnd + trailer.length);
72
+ input.set(data, 0);
73
+ input.set(packet.subarray(0, hashedEnd), data.length);
74
+ input.set(trailer, data.length + hashedEnd);
75
+ const digest = hash(input);
76
+ return [packet[left16] << 8 | packet[left16 + 1], digest[0] << 8 | digest[1]];
77
+ }
78
+ function gpgSignatureCovers(blob, message) {
79
+ const packets = signaturePackets(dearmor(blob));
80
+ if (!packets.length) throw new Error("The PGP SIGNATURE block holds no signature");
81
+ const bytes = new TextEncoder().encode(message);
82
+ return packets.every(packet => {
83
+ const [expected, actual] = quickCheck(packet, bytes);
84
+ return expected === actual;
85
+ });
86
+ }
87
+ export { gpgSignatureCovers };
88
+ //# sourceMappingURL=signature.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ripemd160","sha1","sha224","sha256","sha384","sha512","BEGIN","END","hashes","dearmor","text","start","indexOf","end","Error","lines","slice","length","split","map","line","trim","blank","hasHeaders","some","includes","body","filter","test","binary","atob","join","Uint8Array","from","c","charCodeAt","signaturePackets","bytes","packets","at","ctb","tag","first","DataView","buffer","byteOffset","getUint32","size","i","push","subarray","quickCheck","packet","message","sigType","toString","hash","hashedEnd","unhashedLength","left16","data","TextEncoder","encode","TextDecoder","decode","replace","trailer","setUint32","input","set","digest","gpgSignatureCovers","blob","every","expected","actual"],"sources":["../../src/signature.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,96 @@
1
+ import { ripemd160, sha1 } from "@noble/hashes/legacy.js";
2
+ import { sha224, sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
3
+ var BEGIN = "-----BEGIN PGP SIGNATURE-----";
4
+ var END = "-----END PGP SIGNATURE-----";
5
+ var hashes = {
6
+ 2: sha1,
7
+ 3: ripemd160,
8
+ 8: sha256,
9
+ 9: sha384,
10
+ 10: sha512,
11
+ 11: sha224
12
+ };
13
+ function dearmor(text) {
14
+ var start = text.indexOf(BEGIN);
15
+ var end = text.indexOf(END, start);
16
+ if (start < 0 || end < 0) throw new Error("No PGP SIGNATURE block in the paste");
17
+ var lines = text.slice(start + BEGIN.length, end).split(/\r?\n/).map(function (line) {
18
+ return line.trim();
19
+ });
20
+ var blank = lines.indexOf("", 1);
21
+ var hasHeaders = lines.slice(1, blank < 0 ? 0 : blank).some(function (line) {
22
+ return line.includes(": ");
23
+ });
24
+ var body = (hasHeaders ? lines.slice(blank) : lines).filter(function (line) {
25
+ return line && !/^=[A-Za-z0-9+/]{4}$/.test(line);
26
+ });
27
+ var binary = atob(body.join(""));
28
+ return Uint8Array.from(binary, function (c) {
29
+ return c.charCodeAt(0);
30
+ });
31
+ }
32
+ function signaturePackets(bytes) {
33
+ var packets = [];
34
+ var at = 0;
35
+ while (at < bytes.length) {
36
+ var ctb = bytes[at++];
37
+ if (!(ctb & 128)) throw new Error("The PGP SIGNATURE block is not OpenPGP data");
38
+ var tag = void 0;
39
+ var length = void 0;
40
+ if (ctb & 64) {
41
+ tag = ctb & 63;
42
+ var first = bytes[at++];
43
+ if (first < 192) length = first;else if (first < 224) length = (first - 192 << 8) + bytes[at++] + 192;else if (first === 255) {
44
+ length = new DataView(bytes.buffer, bytes.byteOffset + at, 4).getUint32(0);
45
+ at += 4;
46
+ } else throw new Error("Partial-length PGP packets are not a detached signature");
47
+ } else {
48
+ tag = ctb >> 2 & 15;
49
+ var size = [1, 2, 4][ctb & 3];
50
+ if (size === void 0) throw new Error("Indeterminate-length PGP packets are not supported");
51
+ length = 0;
52
+ for (var i = 0; i < size; i++) length = length * 256 + bytes[at++];
53
+ }
54
+ if (at + length > bytes.length) throw new Error("The PGP SIGNATURE block is truncated");
55
+ if (tag === 2) packets.push(bytes.subarray(at, at + length));
56
+ at += length;
57
+ }
58
+ return packets;
59
+ }
60
+ function quickCheck(packet, message) {
61
+ if (packet[0] !== 4) {
62
+ throw new Error(`A version ${packet[0]} PGP signature cannot be checked here; sign with a v4 key`);
63
+ }
64
+ var sigType = packet[1];
65
+ if (sigType !== 0 && sigType !== 1) {
66
+ throw new Error(`PGP signature type 0x${sigType.toString(16)} is not a document signature`);
67
+ }
68
+ var hash = hashes[packet[3]];
69
+ if (!hash) throw new Error(`PGP hash algorithm ${packet[3]} is not supported`);
70
+ var hashedEnd = 6 + (packet[4] << 8 | packet[5]);
71
+ var unhashedLength = packet[hashedEnd] << 8 | packet[hashedEnd + 1];
72
+ var left16 = hashedEnd + 2 + unhashedLength;
73
+ if (left16 + 2 > packet.length) throw new Error("The PGP signature packet is truncated");
74
+ var data = sigType === 1 ? new TextEncoder().encode(new TextDecoder().decode(message).replace(/\r?\n/g, "\n").replace(/\n/g, "\r\n")) : message;
75
+ var trailer = new Uint8Array(6);
76
+ trailer[0] = 4;
77
+ trailer[1] = 255;
78
+ new DataView(trailer.buffer).setUint32(2, hashedEnd);
79
+ var input = new Uint8Array(data.length + hashedEnd + trailer.length);
80
+ input.set(data, 0);
81
+ input.set(packet.subarray(0, hashedEnd), data.length);
82
+ input.set(trailer, data.length + hashedEnd);
83
+ var digest = hash(input);
84
+ return [packet[left16] << 8 | packet[left16 + 1], digest[0] << 8 | digest[1]];
85
+ }
86
+ function gpgSignatureCovers(blob, message) {
87
+ var packets = signaturePackets(dearmor(blob));
88
+ if (!packets.length) throw new Error("The PGP SIGNATURE block holds no signature");
89
+ var bytes = new TextEncoder().encode(message);
90
+ return packets.every(function (packet) {
91
+ var [expected, actual] = quickCheck(packet, bytes);
92
+ return expected === actual;
93
+ });
94
+ }
95
+ export { gpgSignatureCovers };
96
+ //# sourceMappingURL=signature.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ripemd160","sha1","sha224","sha256","sha384","sha512","BEGIN","END","hashes","dearmor","text","start","indexOf","end","Error","lines","slice","length","split","map","line","trim","blank","hasHeaders","some","includes","body","filter","test","binary","atob","join","Uint8Array","from","c","charCodeAt","signaturePackets","bytes","packets","at","ctb","tag","first","DataView","buffer","byteOffset","getUint32","size","i","push","subarray","quickCheck","packet","message","sigType","toString","hash","hashedEnd","unhashedLength","left16","data","TextEncoder","encode","TextDecoder","decode","replace","trailer","setUint32","input","set","digest"],"sources":["../../src/signature.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,88 @@
1
+ import { useSyncExternalStore } from "react";
2
+ import { gpgSignatureCovers } from "./signature.mjs";
3
+ import { gpgSignatureCovers as gpgSignatureCovers2 } from "./signature.mjs";
4
+ const GPG_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----";
5
+ const GPG_PUBLIC_KEY_BEGIN = "-----BEGIN PGP PUBLIC KEY BLOCK-----";
6
+ function gpgSignCommand(message) {
7
+ return `{ printf %s '${message.replace(/'/g, "'\\''")}' | gpg --detach-sign --armor; gpg --armor --export; }`;
8
+ }
9
+ function assertGpgSignature(blob) {
10
+ const trimmed = blob.trim();
11
+ if (!trimmed.includes(GPG_SIGNATURE_BEGIN) || !trimmed.includes(GPG_PUBLIC_KEY_BEGIN)) {
12
+ throw new Error("Paste the FULL output \u2014 it must contain both a PGP SIGNATURE and a PUBLIC KEY block.");
13
+ }
14
+ return trimmed;
15
+ }
16
+ function createGpgSigner() {
17
+ let pending = null;
18
+ let settle = null;
19
+ const listeners = /* @__PURE__ */new Set();
20
+ const emit = () => {
21
+ for (const listener of listeners) listener();
22
+ };
23
+ const signer = {
24
+ family: "gpg",
25
+ address: null,
26
+ capabilities: ["signMessage"],
27
+ get pending() {
28
+ return pending;
29
+ },
30
+ signMessage(message) {
31
+ settle?.reject(new Error("GPG signing was superseded by a newer request"));
32
+ return new Promise((resolve, reject) => {
33
+ settle = {
34
+ resolve,
35
+ reject
36
+ };
37
+ pending = {
38
+ message,
39
+ command: gpgSignCommand(message)
40
+ };
41
+ emit();
42
+ });
43
+ },
44
+ submit(blob, request) {
45
+ if (!settle || !pending) throw new Error("No GPG signature was requested");
46
+ if (request !== pending) {
47
+ throw new Error("That GPG request was superseded; run the current command and paste its output");
48
+ }
49
+ const signature = assertGpgSignature(blob);
50
+ if (!gpgSignatureCovers(signature, pending.message)) {
51
+ throw new Error("That signature is over a different message; run the current command and paste its output");
52
+ }
53
+ const {
54
+ resolve
55
+ } = settle;
56
+ settle = null;
57
+ pending = null;
58
+ emit();
59
+ resolve(signature);
60
+ },
61
+ cancel(reason) {
62
+ if (!settle) return;
63
+ const {
64
+ reject
65
+ } = settle;
66
+ settle = null;
67
+ pending = null;
68
+ emit();
69
+ reject(reason ?? new Error("GPG signing was cancelled"));
70
+ },
71
+ subscribe(listener) {
72
+ listeners.add(listener);
73
+ return () => listeners.delete(listener);
74
+ }
75
+ };
76
+ return signer;
77
+ }
78
+ function useGpgSigner(signer = defaultSigner()) {
79
+ useSyncExternalStore(signer.subscribe, () => signer.pending, () => signer.pending);
80
+ return signer;
81
+ }
82
+ let sharedSigner = null;
83
+ function defaultSigner() {
84
+ sharedSigner ??= createGpgSigner();
85
+ return sharedSigner;
86
+ }
87
+ export { GPG_PUBLIC_KEY_BEGIN, GPG_SIGNATURE_BEGIN, assertGpgSignature, createGpgSigner, gpgSignCommand, gpgSignatureCovers2 as gpgSignatureCovers, useGpgSigner };
88
+ //# sourceMappingURL=signer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useSyncExternalStore","gpgSignatureCovers","gpgSignatureCovers2","GPG_SIGNATURE_BEGIN","GPG_PUBLIC_KEY_BEGIN","gpgSignCommand","message","replace","assertGpgSignature","blob","trimmed","trim","includes","Error","createGpgSigner","pending","settle","listeners","Set","emit","listener","signer","family","address","capabilities","signMessage","reject","Promise","resolve","command","submit","request","signature","cancel","reason","subscribe","add","delete","useGpgSigner","defaultSigner","sharedSigner"],"sources":["../../src/signer.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,116 @@
1
+ import { useSyncExternalStore } from "react";
2
+ import { gpgSignatureCovers } from "./signature.native.js";
3
+ import { gpgSignatureCovers as gpgSignatureCovers2 } from "./signature.native.js";
4
+ var GPG_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----";
5
+ var GPG_PUBLIC_KEY_BEGIN = "-----BEGIN PGP PUBLIC KEY BLOCK-----";
6
+ function gpgSignCommand(message) {
7
+ return `{ printf %s '${message.replace(/'/g, "'\\''")}' | gpg --detach-sign --armor; gpg --armor --export; }`;
8
+ }
9
+ function assertGpgSignature(blob) {
10
+ var trimmed = blob.trim();
11
+ if (!trimmed.includes(GPG_SIGNATURE_BEGIN) || !trimmed.includes(GPG_PUBLIC_KEY_BEGIN)) {
12
+ throw new Error("Paste the FULL output \u2014 it must contain both a PGP SIGNATURE and a PUBLIC KEY block.");
13
+ }
14
+ return trimmed;
15
+ }
16
+ function createGpgSigner() {
17
+ var pending = null;
18
+ var settle = null;
19
+ var listeners = /* @__PURE__ */new Set();
20
+ var emit = function emit2() {
21
+ var _iteratorNormalCompletion = true,
22
+ _didIteratorError = false,
23
+ _iteratorError = void 0;
24
+ try {
25
+ for (var _iterator = listeners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
26
+ var listener = _step.value;
27
+ listener();
28
+ }
29
+ } catch (err) {
30
+ _didIteratorError = true;
31
+ _iteratorError = err;
32
+ } finally {
33
+ try {
34
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
35
+ _iterator.return();
36
+ }
37
+ } finally {
38
+ if (_didIteratorError) {
39
+ throw _iteratorError;
40
+ }
41
+ }
42
+ }
43
+ };
44
+ var signer = {
45
+ family: "gpg",
46
+ address: null,
47
+ capabilities: ["signMessage"],
48
+ get pending() {
49
+ return pending;
50
+ },
51
+ signMessage(message) {
52
+ settle === null || settle === void 0 ? void 0 : settle.reject(new Error("GPG signing was superseded by a newer request"));
53
+ return new Promise(function (resolve, reject) {
54
+ settle = {
55
+ resolve,
56
+ reject
57
+ };
58
+ pending = {
59
+ message,
60
+ command: gpgSignCommand(message)
61
+ };
62
+ emit();
63
+ });
64
+ },
65
+ submit(blob, request) {
66
+ if (!settle || !pending) throw new Error("No GPG signature was requested");
67
+ if (request !== pending) {
68
+ throw new Error("That GPG request was superseded; run the current command and paste its output");
69
+ }
70
+ var signature = assertGpgSignature(blob);
71
+ if (!gpgSignatureCovers(signature, pending.message)) {
72
+ throw new Error("That signature is over a different message; run the current command and paste its output");
73
+ }
74
+ var {
75
+ resolve
76
+ } = settle;
77
+ settle = null;
78
+ pending = null;
79
+ emit();
80
+ resolve(signature);
81
+ },
82
+ cancel(reason) {
83
+ if (!settle) return;
84
+ var {
85
+ reject
86
+ } = settle;
87
+ settle = null;
88
+ pending = null;
89
+ emit();
90
+ reject(reason !== null && reason !== void 0 ? reason : new Error("GPG signing was cancelled"));
91
+ },
92
+ subscribe(listener) {
93
+ listeners.add(listener);
94
+ return function () {
95
+ return listeners.delete(listener);
96
+ };
97
+ }
98
+ };
99
+ return signer;
100
+ }
101
+ function useGpgSigner() {
102
+ var signer = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : defaultSigner();
103
+ useSyncExternalStore(signer.subscribe, function () {
104
+ return signer.pending;
105
+ }, function () {
106
+ return signer.pending;
107
+ });
108
+ return signer;
109
+ }
110
+ var sharedSigner = null;
111
+ function defaultSigner() {
112
+ sharedSigner !== null && sharedSigner !== void 0 ? sharedSigner : sharedSigner = createGpgSigner();
113
+ return sharedSigner;
114
+ }
115
+ export { GPG_PUBLIC_KEY_BEGIN, GPG_SIGNATURE_BEGIN, assertGpgSignature, createGpgSigner, gpgSignCommand, gpgSignatureCovers2 as gpgSignatureCovers, useGpgSigner };
116
+ //# sourceMappingURL=signer.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useSyncExternalStore","gpgSignatureCovers","gpgSignatureCovers2","GPG_SIGNATURE_BEGIN","GPG_PUBLIC_KEY_BEGIN","gpgSignCommand","message","replace","assertGpgSignature","blob","trimmed","trim","includes","Error","createGpgSigner","pending","settle","listeners","Set","emit","emit2","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","Symbol","iterator","_step","next","done","listener","value","err","return","signer","family","address","capabilities","signMessage","reject","Promise","resolve","command","submit","request","signature","cancel","reason"],"sources":["../../src/signer.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,oBAAA,QAA4B;AACrC,SAASC,kBAAA,QAA0B;AAEnC,SAASA,kBAAA,IAAAC,mBAAA,QAA0B;AAS5B,IAAAC,mBAAM,kCAAsB;AAC5B,IAAAC,oBAAM,yCAAuB;AAQ7B,SAASC,eAAeC,OAAA,EAAyB;EACtD,OAAO,gBAAgBA,OAAA,CAAQC,OAAA,CAAQ,MAAM,OAAO,CAAC;AACvD;AAGO,SAASC,mBAAmBC,IAAA,EAAsB;EACvD,IAAAC,OAAM,GAAAD,IAAU,CAAAE,IAAK;EACrB,IAAI,CAACD,OAAA,CAAQE,QAAA,CAAST,mBAAmB,KAAK,CAACO,OAAA,CAAQE,QAAA,CAASR,oBAAoB,GAAG;IACrF,MAAM,IAAIS,KAAA;EAAA;EACR,OACFH,OAAA;AAAA;AAEF,SAAOI,gBAAA;EACT,IAAAC,OAAA;EA+BO,IAAAC,MAAS;EACd,IAAIC,SAAA,GAAiC,mBAAAC,GAAA;EACrC,IAAIC,IAAA,YAAqFC,MAAA;IACzF,IAAMC,yBAAY,OAAI;MAAAC,iBAAgB;MAAAC,cAAA;IACtC,IAAM;MACJ,SAAWC,SAAA,GAAYP,SAAA,CAAWQ,MAAA,CAAAC,QAAS,KAAAC,KAAA,IAAAN,yBAAA,IAAAM,KAAA,GAAAH,SAAA,CAAAI,IAAA,IAAAC,IAAA,GAAAR,yBAAA;QAC7C,IAAAS,QAAA,GAAAH,KAAA,CAAAI,KAAA;QAEMD,QAAA,CAAoB;MACxB;IACA,SAASE,GAAA;MACTV,iBAAe;MACfC,cAAc,GAAAS,GAAA;IACZ,UAAO;MACT;QACA,KAAAX,yBAAqB,IAAAG,SAAA,CAAAS,MAAA;UACnBT,SAAQ,CAAAS,MAAW;QACnB;MACE;QACA,IAAAX,iBAAqB;UACrB,MAAKC,cAAA;QACN;MACH;IACA;EACE;EACA,IAAAW,MAAI;IACFC,MAAA,OAAM;IAAIC,OACR;IAAAC,YACF,GACF,cACA;IACA,IAAAtB,OAAKA,CAAA;MACH,OAAAA,OAAU;IAAA;IACRuB,WACFA,CAAAhC,OAAA;MACFU,MAAA,aAAAA,MAAA,uBAAAA,MAAA,CAAAuB,MAAA,KAAA1B,KAAA;MACA,OAAM,IAAE2B,OAAQ,WAAIC,OAAA,EAAAF,MAAA;QACpBvB,MAAA,GAAS;UACTyB,OAAU;UACVF;QACA;QACFxB,OAAA;UACAT,OAAO;UACDoC,OAAC,EAAQrC,cAAA,CAAAC,OAAA;QACb;QACAa,IAAA;MACA;IACA;IACAwB,OAAAlC,IAAO,EAAAmC,OAAU;MACnB,KAAA5B,MAAA,KAAAD,OAAA,YAAAF,KAAA;MACA,IAAA+B,OAAU,KAAA7B,OAAU;QAClB,UAAUF,KAAI,gFAAQ;MACtB;MACF,IAAAgC,SAAA,GAAArC,kBAAA,CAAAC,IAAA;MACF,KAAAR,kBAAA,CAAA4C,SAAA,EAAA9B,OAAA,CAAAT,OAAA;QACA,MAAO,IAAAO,KAAA;MACT;MAOO,IAAS;QAAA4B;MAAA,IAAazB,MAAA;MAC3BA,MAAA;MACED,OAAO;MACPI,IAAM;MACNsB,OAAM,CAAAI,SAAO;IACf;IACAC,MAAOA,CAAAC,MAAA;MACT,KAAA/B,MAAA;MAEI;QAAAuB;MAAiC,IAAAvB,MAAA;MACrCA,MAAS;MACPD,OAAA,OAAiB;MACjBI,IAAO;MACToB,MAAA,CAAAQ,MAAA,aAAAA,MAAA,cAAAA,MAAA,OAAAlC,KAAA","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/gpg",
3
- "version": "7.17.0",
3
+ "version": "7.19.0",
4
4
  "description": "Sign-In With GPG (SIWG) screen + GpgProvider for the connectkit modal — no viem",
5
5
  "keywords": [
6
6
  "connectkit",
@@ -49,16 +49,29 @@
49
49
  "types": "./types/index.d.ts",
50
50
  "import": "./dist/esm/index.mjs",
51
51
  "require": "./dist/cjs/index.cjs"
52
+ },
53
+ "./signer": {
54
+ "source": "./src/signer.ts",
55
+ "react-native": {
56
+ "types": "./types/signer.d.ts",
57
+ "import": "./src/signer.ts",
58
+ "require": "./src/signer.ts",
59
+ "default": "./src/signer.ts"
60
+ },
61
+ "types": "./types/signer.d.ts",
62
+ "import": "./dist/esm/signer.mjs",
63
+ "require": "./dist/cjs/signer.cjs"
52
64
  }
53
65
  },
54
66
  "publishConfig": {
55
67
  "access": "public"
56
68
  },
57
69
  "dependencies": {
58
- "@multiplatform.one/connectkit": "7.17.0"
70
+ "@multiplatform.one/connectkit": "7.19.0",
71
+ "@noble/hashes": "^1.8.0"
59
72
  },
60
73
  "devDependencies": {
61
- "@multiplatform.one/config": "7.17.0",
74
+ "@multiplatform.one/config": "7.19.0",
62
75
  "@tamagui/build": "2.7.6",
63
76
  "react": "19.2.5",
64
77
  "typescript": "~5.9.3"
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+
3
+ // The GPG row's icon in the wallet list: a key on GnuPG blue, filling the row's
4
+ // icon box like the wallet logos beside it.
5
+ export const GpgIcon: React.FC = () => (
6
+ <svg
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ width="100%"
9
+ height="100%"
10
+ viewBox="0 0 32 32"
11
+ aria-hidden="true"
12
+ >
13
+ <rect width="32" height="32" fill="#0093DD" />
14
+ <g fill="none" stroke="#FFFFFF" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
15
+ <circle cx="11.5" cy="19.5" r="4.5" />
16
+ <path d="m14.7 16.3 9.3-9.3" />
17
+ <path d="m20 11 3 3 2.5-2.5-3-3" />
18
+ </g>
19
+ </svg>
20
+ );
@@ -3,6 +3,7 @@ import { useQuery } from "@tanstack/react-query";
3
3
 
4
4
  import { Context as ConnectKitContext } from "@multiplatform.one/connectkit";
5
5
  import { GpgContext, GpgConfig, GpgStatusState } from "./GpgContext";
6
+ import { assertGpgSignature, gpgSignCommand } from "./signer";
6
7
 
7
8
  type Props = GpgConfig & {
8
9
  children: ReactNode;
@@ -71,28 +72,15 @@ export const GpgProvider = ({
71
72
  nonce.data ? (buildMessageRef.current ?? defaultBuildMessage)({ nonce: nonce.data }) : null,
72
73
  [nonce.data],
73
74
  );
74
- // The ready-to-run terminal command: detached armored signature + the exported public
75
- // key, concatenated — exactly the blob the user pastes back. printf %s (no newline) so
76
- // the signed bytes are byte-identical to `message`. Single quotes in the message are
77
- // POSIX-escaped ('\'' ) so a custom buildMessage can't break out of the quoting.
78
- const command = useMemo(
79
- () =>
80
- message
81
- ? `{ printf %s '${message.replace(/'/g, "'\\''")}' | gpg --detach-sign --armor; gpg --armor --export; }`
82
- : null,
83
- [message],
84
- );
75
+ const command = useMemo(() => (message ? gpgSignCommand(message) : null), [message]);
85
76
 
86
77
  const signIn = async (pastedBlob: string): Promise<boolean> => {
87
- const blob = pastedBlob.trim();
88
- if (
89
- !blob.includes("-----BEGIN PGP SIGNATURE-----") ||
90
- !blob.includes("-----BEGIN PGP PUBLIC KEY BLOCK-----")
91
- ) {
78
+ let blob: string;
79
+ try {
80
+ blob = assertGpgSignature(pastedBlob);
81
+ } catch (error) {
92
82
  setStatus(GpgStatusState.ERROR);
93
- throw new Error(
94
- "Paste the FULL output — it must contain both a PGP SIGNATURE and a PUBLIC KEY block.",
95
- );
83
+ throw error;
96
84
  }
97
85
  if (!message) {
98
86
  setStatus(GpgStatusState.ERROR);
package/src/index.ts CHANGED
@@ -2,8 +2,17 @@
2
2
  //
3
3
  // A connection-free signer: the user signs a challenge in their terminal and pastes
4
4
  // the result back. Pulls in NO wagmi/viem — depends only on @multiplatform.one/connectkit
5
- // — so a GPG-only app can install it without the wallet stack.
5
+ // and @noble/hashes — so a GPG-only app can install it without the wallet stack.
6
6
  export { useGpg } from "./useGpg";
7
+ export {
8
+ createGpgSigner,
9
+ useGpgSigner,
10
+ gpgSignCommand,
11
+ assertGpgSignature,
12
+ gpgSignatureCovers,
13
+ type GpgSigner,
14
+ type GpgSignRequest,
15
+ } from "./signer";
7
16
  export { GpgProvider, GPG_NONCE_QUERY_KEY } from "./GpgProvider";
8
17
  export { GpgContext, GpgStatusState } from "./GpgContext";
9
18
  export type { GpgConfig, GpgContextValue } from "./GpgContext";
package/src/screens.tsx CHANGED
@@ -9,16 +9,26 @@ import {
9
9
  import { useContext as useReactContext } from "react";
10
10
  import SignInWithGpg from "./SignInWithGpg";
11
11
  import { GpgContext } from "./GpgContext";
12
+ import { GpgIcon } from "./GpgIcon";
12
13
 
13
14
  // The GPG screen contributed to connectkit's signer-agnostic modal. GPG has no
14
15
  // connect step, so it's available in both connected and disconnected states.
16
+ // With a wallet bridge it is also a row in the wallet list, next to MetaMask and
17
+ // Phantom, and while disconnected its back chevron returns to that list. A
18
+ // gpg-only host has no list (no `connected` in its state), so no back there.
15
19
  export const gpgScreen: ScreenDef = {
16
20
  id: routes.SIGNINWITHGPG,
17
21
  component: SignInWithGpg,
18
22
  heading: "Sign in with GPG",
19
23
  availableWhen: () => true,
20
- showBack: false,
24
+ showBack: (state) => state.connected === false,
25
+ onBack: (api) => api.setRoute(routes.CONNECTORS),
21
26
  showInfo: false,
27
+ listEntry: {
28
+ name: "GPG",
29
+ icon: <GpgIcon />,
30
+ visibleWhen: (state) => !!state.signInWithGpg,
31
+ },
22
32
  };
23
33
 
24
34
  /**