@solana/keychain-gcp-kms 0.6.1 → 1.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/dist/__tests__/gcp-kms-signer.test.js +152 -76
- package/dist/__tests__/gcp-kms-signer.test.js.map +1 -1
- package/dist/gcp-kms-signer.d.ts +6 -1
- package/dist/gcp-kms-signer.d.ts.map +1 -1
- package/dist/gcp-kms-signer.js +89 -24
- package/dist/gcp-kms-signer.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/gcp-kms-signer.test.ts +201 -76
- package/src/gcp-kms-signer.ts +111 -24
|
@@ -1,31 +1,66 @@
|
|
|
1
1
|
import { address } from '@solana/addresses';
|
|
2
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import { assertIsSolanaSigner } from '@solana/keychain-core';
|
|
4
4
|
import { GcpKmsSigner } from '../gcp-kms-signer.js';
|
|
5
5
|
vi.mock('@solana/keychain-core', async (importOriginal) => {
|
|
6
6
|
const mod = await importOriginal();
|
|
7
|
-
return {
|
|
7
|
+
return {
|
|
8
|
+
...mod,
|
|
9
|
+
assertSignatureValid: vi.fn(),
|
|
10
|
+
sanitizeRemoteErrorResponse: mod.sanitizeRemoteErrorResponse ??
|
|
11
|
+
((text) => text
|
|
12
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, ' ')
|
|
13
|
+
.replace(/\s+/g, ' ')
|
|
14
|
+
.trim()
|
|
15
|
+
.slice(0, 256)),
|
|
16
|
+
};
|
|
8
17
|
});
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
vi.mock('
|
|
18
|
+
const mockGetRequestHeaders = vi.fn();
|
|
19
|
+
const mockFetch = vi.fn();
|
|
20
|
+
const originalFetch = globalThis.fetch;
|
|
21
|
+
vi.mock('google-auth-library', () => {
|
|
13
22
|
return {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.getPublicKey = mockGetPublicKey;
|
|
19
|
-
}
|
|
20
|
-
},
|
|
23
|
+
GoogleAuth: class {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.getRequestHeaders = mockGetRequestHeaders;
|
|
26
|
+
}
|
|
21
27
|
},
|
|
22
28
|
};
|
|
23
29
|
});
|
|
30
|
+
function createJsonResponse(body, status = 200) {
|
|
31
|
+
return new Response(JSON.stringify(body), {
|
|
32
|
+
status,
|
|
33
|
+
headers: { 'content-type': 'application/json' },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function getFetchCall(index) {
|
|
37
|
+
return mockFetch.mock.calls[index];
|
|
38
|
+
}
|
|
39
|
+
function assertAuthorizedRequest(url, method, callIndex = 0) {
|
|
40
|
+
const [calledUrl, init] = getFetchCall(callIndex);
|
|
41
|
+
expect(calledUrl).toBe(url);
|
|
42
|
+
expect(init.method).toBe(method);
|
|
43
|
+
const headers = new Headers(init.headers);
|
|
44
|
+
expect(headers.get('authorization')).toBe('Bearer test-token');
|
|
45
|
+
return init;
|
|
46
|
+
}
|
|
24
47
|
describe('GcpKmsSigner', () => {
|
|
25
48
|
const TEST_KEY_NAME = 'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1';
|
|
49
|
+
const TEST_KEY_NAME_WITH_LEADING_SLASH = `/${TEST_KEY_NAME}`;
|
|
26
50
|
const TEST_PUBLIC_KEY = address('11111111111111111111111111111111');
|
|
51
|
+
const SIGN_ENDPOINT = `https://cloudkms.googleapis.com/v1/${TEST_KEY_NAME}:asymmetricSign`;
|
|
52
|
+
const PUBLIC_KEY_ENDPOINT = `https://cloudkms.googleapis.com/v1/${TEST_KEY_NAME}/publicKey`;
|
|
53
|
+
const TEST_SIGNATURE_BYTES = new Uint8Array(64).fill(0x42);
|
|
54
|
+
const TEST_SIGNATURE_BASE64 = Buffer.from(TEST_SIGNATURE_BYTES).toString('base64');
|
|
55
|
+
beforeAll(() => {
|
|
56
|
+
globalThis.fetch = mockFetch;
|
|
57
|
+
});
|
|
27
58
|
beforeEach(() => {
|
|
28
59
|
vi.clearAllMocks();
|
|
60
|
+
mockGetRequestHeaders.mockResolvedValue(new Headers({ authorization: 'Bearer test-token' }));
|
|
61
|
+
});
|
|
62
|
+
afterAll(() => {
|
|
63
|
+
globalThis.fetch = originalFetch;
|
|
29
64
|
});
|
|
30
65
|
describe('create', () => {
|
|
31
66
|
it('creates a GcpKmsSigner with valid config', () => {
|
|
@@ -82,6 +117,33 @@ describe('GcpKmsSigner', () => {
|
|
|
82
117
|
});
|
|
83
118
|
}).toThrow('Invalid Solana public key format');
|
|
84
119
|
});
|
|
120
|
+
it('should throw error for invalid keyName format', () => {
|
|
121
|
+
const invalidKeyNames = [
|
|
122
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1#',
|
|
123
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1?',
|
|
124
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/%31',
|
|
125
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key//cryptoKeyVersions/1',
|
|
126
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key',
|
|
127
|
+
];
|
|
128
|
+
for (const keyName of invalidKeyNames) {
|
|
129
|
+
expect(() => {
|
|
130
|
+
new GcpKmsSigner({
|
|
131
|
+
keyName,
|
|
132
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
133
|
+
});
|
|
134
|
+
}).toThrow('Invalid GCP KMS keyName format');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
it('should canonicalize leading slashes in keyName', async () => {
|
|
138
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
139
|
+
const signer = new GcpKmsSigner({
|
|
140
|
+
keyName: TEST_KEY_NAME_WITH_LEADING_SLASH,
|
|
141
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
142
|
+
});
|
|
143
|
+
await signer.signMessages([{ content: new Uint8Array([1, 2, 3]), signatures: {} }]);
|
|
144
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
145
|
+
assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
146
|
+
});
|
|
85
147
|
it('should validate requestDelayMs', () => {
|
|
86
148
|
expect(() => {
|
|
87
149
|
new GcpKmsSigner({
|
|
@@ -104,11 +166,7 @@ describe('GcpKmsSigner', () => {
|
|
|
104
166
|
});
|
|
105
167
|
describe('signMessages', () => {
|
|
106
168
|
it('should sign a message successfully', async () => {
|
|
107
|
-
|
|
108
|
-
{
|
|
109
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
110
|
-
},
|
|
111
|
-
]);
|
|
169
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
112
170
|
const signer = new GcpKmsSigner({
|
|
113
171
|
keyName: TEST_KEY_NAME,
|
|
114
172
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -120,18 +178,30 @@ describe('GcpKmsSigner', () => {
|
|
|
120
178
|
const result = await signer.signMessages([message]);
|
|
121
179
|
expect(result).toHaveLength(1);
|
|
122
180
|
expect(result[0]?.[signer.address]).toBeDefined();
|
|
123
|
-
expect(
|
|
124
|
-
expect(
|
|
125
|
-
|
|
126
|
-
|
|
181
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
182
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
183
|
+
const init = assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
184
|
+
const headers = new Headers(init.headers);
|
|
185
|
+
expect(headers.get('content-type')).toBe('application/json');
|
|
186
|
+
expect(init.body).toBe(JSON.stringify({
|
|
187
|
+
data: Buffer.from(message.content).toString('base64'),
|
|
188
|
+
}));
|
|
189
|
+
});
|
|
190
|
+
it('should build sign URL without fragments or queries for valid keyName', async () => {
|
|
191
|
+
const signer = new GcpKmsSigner({
|
|
192
|
+
keyName: TEST_KEY_NAME,
|
|
193
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
127
194
|
});
|
|
195
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
196
|
+
await signer.signMessages([{ content: new Uint8Array([1, 2, 3, 4]), signatures: {} }]);
|
|
197
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
198
|
+
const [calledUrl] = getFetchCall(0);
|
|
199
|
+
expect(calledUrl).toBe(SIGN_ENDPOINT);
|
|
200
|
+
expect(calledUrl).not.toContain('#');
|
|
201
|
+
expect(calledUrl).not.toContain('?');
|
|
128
202
|
});
|
|
129
203
|
it('should handle multiple messages with delay', async () => {
|
|
130
|
-
|
|
131
|
-
{
|
|
132
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
133
|
-
},
|
|
134
|
-
]);
|
|
204
|
+
mockFetch.mockImplementation(() => Promise.resolve(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 })));
|
|
135
205
|
const signer = new GcpKmsSigner({
|
|
136
206
|
keyName: TEST_KEY_NAME,
|
|
137
207
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -146,16 +216,12 @@ describe('GcpKmsSigner', () => {
|
|
|
146
216
|
const result = await signer.signMessages(messages);
|
|
147
217
|
const endTime = Date.now();
|
|
148
218
|
expect(result).toHaveLength(3);
|
|
149
|
-
expect(
|
|
150
|
-
// Should have some delay (at least 15ms for 2 delays of 10ms each)
|
|
219
|
+
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
151
220
|
expect(endTime - startTime).toBeGreaterThanOrEqual(15);
|
|
152
221
|
});
|
|
153
222
|
it('should throw error on invalid signature length', async () => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
signature: new Uint8Array(32), // Wrong length
|
|
157
|
-
},
|
|
158
|
-
]);
|
|
223
|
+
const shortSignature = Buffer.from(new Uint8Array(32).fill(0x42)).toString('base64');
|
|
224
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: shortSignature }));
|
|
159
225
|
const signer = new GcpKmsSigner({
|
|
160
226
|
keyName: TEST_KEY_NAME,
|
|
161
227
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -164,7 +230,7 @@ describe('GcpKmsSigner', () => {
|
|
|
164
230
|
await expect(signer.signMessages([message])).rejects.toThrow('Invalid signature length');
|
|
165
231
|
});
|
|
166
232
|
it('should throw error on missing signature', async () => {
|
|
167
|
-
|
|
233
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
168
234
|
const signer = new GcpKmsSigner({
|
|
169
235
|
keyName: TEST_KEY_NAME,
|
|
170
236
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -173,24 +239,31 @@ describe('GcpKmsSigner', () => {
|
|
|
173
239
|
await expect(signer.signMessages([message])).rejects.toThrow('No signature in GCP KMS response');
|
|
174
240
|
});
|
|
175
241
|
it('should handle GCP KMS API errors', async () => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
242
|
+
mockFetch.mockResolvedValue(createJsonResponse({
|
|
243
|
+
error: {
|
|
244
|
+
message: 'GCP Error',
|
|
245
|
+
},
|
|
246
|
+
}, 403));
|
|
179
247
|
const signer = new GcpKmsSigner({
|
|
180
248
|
keyName: TEST_KEY_NAME,
|
|
181
249
|
publicKey: TEST_PUBLIC_KEY,
|
|
182
250
|
});
|
|
183
251
|
const message = { content: new Uint8Array([1, 2, 3, 4]), signatures: {} };
|
|
184
|
-
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS
|
|
252
|
+
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS API error: 403');
|
|
253
|
+
});
|
|
254
|
+
it('should handle network errors', async () => {
|
|
255
|
+
mockFetch.mockRejectedValue(new Error('Network error'));
|
|
256
|
+
const signer = new GcpKmsSigner({
|
|
257
|
+
keyName: TEST_KEY_NAME,
|
|
258
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
259
|
+
});
|
|
260
|
+
const message = { content: new Uint8Array([1, 2, 3, 4]), signatures: {} };
|
|
261
|
+
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS network request failed');
|
|
185
262
|
});
|
|
186
263
|
});
|
|
187
264
|
describe('signTransactions', () => {
|
|
188
265
|
it('should sign a transaction successfully', async () => {
|
|
189
|
-
|
|
190
|
-
{
|
|
191
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
192
|
-
},
|
|
193
|
-
]);
|
|
266
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
194
267
|
const signer = new GcpKmsSigner({
|
|
195
268
|
keyName: TEST_KEY_NAME,
|
|
196
269
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -202,14 +275,11 @@ describe('GcpKmsSigner', () => {
|
|
|
202
275
|
const result = await signer.signTransactions([transaction]);
|
|
203
276
|
expect(result).toHaveLength(1);
|
|
204
277
|
expect(result[0]).toHaveProperty(signer.address);
|
|
205
|
-
expect(
|
|
278
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
279
|
+
assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
206
280
|
});
|
|
207
281
|
it('should sign multiple transactions successfully', async () => {
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
211
|
-
},
|
|
212
|
-
]);
|
|
282
|
+
mockFetch.mockImplementation(() => Promise.resolve(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 })));
|
|
213
283
|
const signer = new GcpKmsSigner({
|
|
214
284
|
keyName: TEST_KEY_NAME,
|
|
215
285
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -220,14 +290,11 @@ describe('GcpKmsSigner', () => {
|
|
|
220
290
|
];
|
|
221
291
|
const result = await signer.signTransactions(transactions);
|
|
222
292
|
expect(result).toHaveLength(2);
|
|
223
|
-
expect(
|
|
293
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
224
294
|
});
|
|
225
295
|
it('should throw error on invalid signature length', async () => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
signature: new Uint8Array(32),
|
|
229
|
-
},
|
|
230
|
-
]);
|
|
296
|
+
const shortSignature = Buffer.from(new Uint8Array(32).fill(0x42)).toString('base64');
|
|
297
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: shortSignature }));
|
|
231
298
|
const signer = new GcpKmsSigner({
|
|
232
299
|
keyName: TEST_KEY_NAME,
|
|
233
300
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -236,7 +303,7 @@ describe('GcpKmsSigner', () => {
|
|
|
236
303
|
await expect(signer.signTransactions([transaction])).rejects.toThrow('Invalid signature length');
|
|
237
304
|
});
|
|
238
305
|
it('should throw error on missing signature', async () => {
|
|
239
|
-
|
|
306
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
240
307
|
const signer = new GcpKmsSigner({
|
|
241
308
|
keyName: TEST_KEY_NAME,
|
|
242
309
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -245,39 +312,44 @@ describe('GcpKmsSigner', () => {
|
|
|
245
312
|
await expect(signer.signTransactions([transaction])).rejects.toThrow('No signature in GCP KMS response');
|
|
246
313
|
});
|
|
247
314
|
it('should handle GCP KMS API errors', async () => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
315
|
+
mockFetch.mockResolvedValue(createJsonResponse({
|
|
316
|
+
error: {
|
|
317
|
+
message: 'GCP Error',
|
|
318
|
+
},
|
|
319
|
+
}, 403));
|
|
251
320
|
const signer = new GcpKmsSigner({
|
|
252
321
|
keyName: TEST_KEY_NAME,
|
|
253
322
|
publicKey: TEST_PUBLIC_KEY,
|
|
254
323
|
});
|
|
255
324
|
const transaction = { messageBytes: new Uint8Array([1, 2, 3, 4]), signatures: {} };
|
|
256
|
-
await expect(signer.signTransactions([transaction])).rejects.toThrow('GCP KMS
|
|
325
|
+
await expect(signer.signTransactions([transaction])).rejects.toThrow('GCP KMS API error: 403');
|
|
257
326
|
});
|
|
258
327
|
});
|
|
259
328
|
describe('isAvailable', () => {
|
|
260
329
|
it('should return true for valid Ed25519 key', async () => {
|
|
261
|
-
|
|
262
|
-
{
|
|
263
|
-
name: TEST_KEY_NAME,
|
|
264
|
-
algorithm: 'EC_SIGN_ED25519',
|
|
265
|
-
},
|
|
266
|
-
]);
|
|
330
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'EC_SIGN_ED25519' }));
|
|
267
331
|
const signer = new GcpKmsSigner({
|
|
268
332
|
keyName: TEST_KEY_NAME,
|
|
269
333
|
publicKey: TEST_PUBLIC_KEY,
|
|
270
334
|
});
|
|
271
335
|
const available = await signer.isAvailable();
|
|
272
336
|
expect(available).toBe(true);
|
|
337
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
338
|
+
assertAuthorizedRequest(PUBLIC_KEY_ENDPOINT, 'GET');
|
|
339
|
+
});
|
|
340
|
+
it('should use canonical public key endpoint for valid key names', async () => {
|
|
341
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'EC_SIGN_ED25519' }));
|
|
342
|
+
const signer = new GcpKmsSigner({
|
|
343
|
+
keyName: TEST_KEY_NAME_WITH_LEADING_SLASH,
|
|
344
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
345
|
+
});
|
|
346
|
+
const available = await signer.isAvailable();
|
|
347
|
+
expect(available).toBe(true);
|
|
348
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(PUBLIC_KEY_ENDPOINT);
|
|
349
|
+
assertAuthorizedRequest(PUBLIC_KEY_ENDPOINT, 'GET');
|
|
273
350
|
});
|
|
274
351
|
it('should return false for wrong algorithm', async () => {
|
|
275
|
-
|
|
276
|
-
{
|
|
277
|
-
name: TEST_KEY_NAME,
|
|
278
|
-
algorithm: 'RSA_SIGN_PKCS1_2048_SHA256',
|
|
279
|
-
},
|
|
280
|
-
]);
|
|
352
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'RSA_SIGN_PKCS1_2048_SHA256' }));
|
|
281
353
|
const signer = new GcpKmsSigner({
|
|
282
354
|
keyName: TEST_KEY_NAME,
|
|
283
355
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -286,7 +358,7 @@ describe('GcpKmsSigner', () => {
|
|
|
286
358
|
expect(available).toBe(false);
|
|
287
359
|
});
|
|
288
360
|
it('should return false for missing public key response', async () => {
|
|
289
|
-
|
|
361
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
290
362
|
const signer = new GcpKmsSigner({
|
|
291
363
|
keyName: TEST_KEY_NAME,
|
|
292
364
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -294,8 +366,12 @@ describe('GcpKmsSigner', () => {
|
|
|
294
366
|
const available = await signer.isAvailable();
|
|
295
367
|
expect(available).toBe(false);
|
|
296
368
|
});
|
|
297
|
-
it('should return false on error', async () => {
|
|
298
|
-
|
|
369
|
+
it('should return false on API error', async () => {
|
|
370
|
+
mockFetch.mockResolvedValue(createJsonResponse({
|
|
371
|
+
error: {
|
|
372
|
+
message: 'Forbidden',
|
|
373
|
+
},
|
|
374
|
+
}, 403));
|
|
299
375
|
const signer = new GcpKmsSigner({
|
|
300
376
|
keyName: TEST_KEY_NAME,
|
|
301
377
|
publicKey: TEST_PUBLIC_KEY,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcp-kms-signer.test.js","sourceRoot":"","sources":["../../src/__tests__/gcp-kms-signer.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gcp-kms-signer.test.js","sourceRoot":"","sources":["../../src/__tests__/gcp-kms-signer.test.ts"],"names":[],"mappings":"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"}
|
package/dist/gcp-kms-signer.d.ts
CHANGED
|
@@ -25,12 +25,17 @@ export declare function createGcpKmsSigner<TAddress extends string = string>(con
|
|
|
25
25
|
export declare class GcpKmsSigner<TAddress extends string = string> implements SolanaSigner<TAddress> {
|
|
26
26
|
readonly address: Address<TAddress>;
|
|
27
27
|
private readonly keyName;
|
|
28
|
-
private readonly
|
|
28
|
+
private readonly keyNamePathSegments;
|
|
29
|
+
private readonly auth;
|
|
29
30
|
private readonly requestDelayMs;
|
|
30
31
|
/** @deprecated Use `createGcpKmsSigner()` instead. */
|
|
31
32
|
static create<TAddress extends string = string>(config: GcpKmsSignerConfig): GcpKmsSigner<TAddress>;
|
|
32
33
|
/** @deprecated Use `createGcpKmsSigner()` instead. Direct construction will be removed in a future version. */
|
|
33
34
|
constructor(config: GcpKmsSignerConfig);
|
|
35
|
+
private normalizeKeyName;
|
|
36
|
+
private buildResourceUrl;
|
|
37
|
+
private authorizedFetch;
|
|
38
|
+
private request;
|
|
34
39
|
/**
|
|
35
40
|
* Validate request delay ms
|
|
36
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcp-kms-signer.d.ts","sourceRoot":"","sources":["../src/gcp-kms-signer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gcp-kms-signer.d.ts","sourceRoot":"","sources":["../src/gcp-kms-signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAKH,YAAY,EAEf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGxG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAoBrD,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAC/D,MAAM,EAAE,kBAAkB,GAC3B,YAAY,CAAC,QAAQ,CAAC,CAExB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAY,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,CAAE,YAAW,YAAY,CAAC,QAAQ,CAAC;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAoB;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,sDAAsD;IACtD,MAAM,CAAC,MAAM,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAAC,QAAQ,CAAC;IAInG,+GAA+G;gBACnG,MAAM,EAAE,kBAAkB;IA8BtC,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;YAOV,eAAe;YAef,OAAO;IAkCrB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAa9B;;OAEG;YACW,KAAK;IAMnB;;OAEG;YACW,SAAS;IAoCvB;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAsBjG;;OAEG;IACG,gBAAgB,CAClB,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,0BAA0B,GAAG,uBAAuB,CAAC,EAAE,GAC9F,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAoB1C;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAgBxC"}
|
package/dist/gcp-kms-signer.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { v1 } from '@google-cloud/kms';
|
|
2
1
|
import { assertIsAddress } from '@solana/addresses';
|
|
3
|
-
import { assertSignatureValid, createSignatureDictionary, SignerErrorCode, throwSignerError, } from '@solana/keychain-core';
|
|
2
|
+
import { assertSignatureValid, createSignatureDictionary, sanitizeRemoteErrorResponse, SignerErrorCode, throwSignerError, } from '@solana/keychain-core';
|
|
3
|
+
import { GoogleAuth } from 'google-auth-library';
|
|
4
|
+
/**
|
|
5
|
+
* Create a Google Cloud KMS-backed signer.
|
|
6
|
+
*
|
|
7
|
+
* @throws {SignerError} `SIGNER_CONFIG_ERROR` when required config is missing or invalid.
|
|
8
|
+
*/
|
|
9
|
+
const CLOUD_KMS_BASE_URL = 'https://cloudkms.googleapis.com/v1';
|
|
10
|
+
const CLOUD_KMS_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
|
|
11
|
+
const ED25519_SIGNATURE_LENGTH = 64;
|
|
12
|
+
const GCP_KMS_KEY_NAME_PATTERN = /^projects\/[A-Za-z0-9._-]+\/locations\/[A-Za-z0-9._-]+\/keyRings\/[A-Za-z0-9._-]+\/cryptoKeys\/[A-Za-z0-9._-]+\/cryptoKeyVersions\/[A-Za-z0-9._-]+$/;
|
|
4
13
|
export function createGcpKmsSigner(config) {
|
|
5
14
|
return GcpKmsSigner.create(config);
|
|
6
15
|
}
|
|
@@ -49,10 +58,74 @@ export class GcpKmsSigner {
|
|
|
49
58
|
message: 'Invalid Solana public key format',
|
|
50
59
|
});
|
|
51
60
|
}
|
|
52
|
-
this.keyName = config.keyName;
|
|
61
|
+
this.keyName = this.normalizeKeyName(config.keyName);
|
|
62
|
+
this.keyNamePathSegments = this.keyName.split('/');
|
|
53
63
|
this.requestDelayMs = config.requestDelayMs || 0;
|
|
54
64
|
this.validateRequestDelayMs(this.requestDelayMs);
|
|
55
|
-
this.
|
|
65
|
+
this.auth = new GoogleAuth({ scopes: [CLOUD_KMS_SCOPE] });
|
|
66
|
+
}
|
|
67
|
+
normalizeKeyName(keyName) {
|
|
68
|
+
const canonicalKeyName = keyName.replace(/^\/+/, '');
|
|
69
|
+
if (/\/{2,}/.test(canonicalKeyName) || /[#?%]/.test(canonicalKeyName)) {
|
|
70
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
71
|
+
message: 'Invalid GCP KMS keyName format',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (!GCP_KMS_KEY_NAME_PATTERN.test(canonicalKeyName)) {
|
|
75
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
76
|
+
message: 'Invalid GCP KMS keyName format',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return canonicalKeyName;
|
|
80
|
+
}
|
|
81
|
+
buildResourceUrl(suffix) {
|
|
82
|
+
const url = new URL(`${CLOUD_KMS_BASE_URL}/`);
|
|
83
|
+
const basePathSegments = url.pathname.split('/').filter(Boolean);
|
|
84
|
+
url.pathname = `/${[...basePathSegments, ...this.keyNamePathSegments].join('/')}${suffix}`;
|
|
85
|
+
return url.toString();
|
|
86
|
+
}
|
|
87
|
+
async authorizedFetch(url, init) {
|
|
88
|
+
const authHeaders = await this.auth.getRequestHeaders(url);
|
|
89
|
+
const headers = new Headers(init.headers);
|
|
90
|
+
authHeaders.forEach((value, key) => {
|
|
91
|
+
headers.set(key, value);
|
|
92
|
+
});
|
|
93
|
+
if (init.body && !headers.has('content-type')) {
|
|
94
|
+
headers.set('content-type', 'application/json');
|
|
95
|
+
}
|
|
96
|
+
return await fetch(url, { ...init, headers });
|
|
97
|
+
}
|
|
98
|
+
async request(url, init) {
|
|
99
|
+
let response;
|
|
100
|
+
try {
|
|
101
|
+
response = await this.authorizedFetch(url, init);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
throwSignerError(SignerErrorCode.HTTP_ERROR, {
|
|
105
|
+
cause: error,
|
|
106
|
+
message: 'GCP KMS network request failed',
|
|
107
|
+
url,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
const errorText = await response.text().catch(() => 'Failed to read error response');
|
|
112
|
+
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
113
|
+
message: `GCP KMS API error: ${response.status}`,
|
|
114
|
+
response: sanitizeRemoteErrorResponse(errorText),
|
|
115
|
+
status: response.status,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
let payload;
|
|
119
|
+
try {
|
|
120
|
+
payload = (await response.json());
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
throwSignerError(SignerErrorCode.PARSING_ERROR, {
|
|
124
|
+
cause: error,
|
|
125
|
+
message: 'Failed to parse GCP KMS response',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return payload;
|
|
56
129
|
}
|
|
57
130
|
/**
|
|
58
131
|
* Validate request delay ms
|
|
@@ -80,10 +153,11 @@ export class GcpKmsSigner {
|
|
|
80
153
|
*/
|
|
81
154
|
async signBytes(messageBytes) {
|
|
82
155
|
try {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
156
|
+
const response = await this.request(this.buildResourceUrl(':asymmetricSign'), {
|
|
157
|
+
body: JSON.stringify({
|
|
158
|
+
data: Buffer.from(messageBytes).toString('base64'),
|
|
159
|
+
}),
|
|
160
|
+
method: 'POST',
|
|
87
161
|
});
|
|
88
162
|
if (!response.signature) {
|
|
89
163
|
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
@@ -91,29 +165,20 @@ export class GcpKmsSigner {
|
|
|
91
165
|
});
|
|
92
166
|
}
|
|
93
167
|
// Ed25519 signatures are 64 bytes
|
|
94
|
-
const signature = response.signature;
|
|
95
|
-
if (signature.length !==
|
|
168
|
+
const signature = new Uint8Array(Buffer.from(response.signature, 'base64'));
|
|
169
|
+
if (signature.length !== ED25519_SIGNATURE_LENGTH) {
|
|
96
170
|
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
97
|
-
message: `Invalid signature length: expected
|
|
171
|
+
message: `Invalid signature length: expected ${ED25519_SIGNATURE_LENGTH} bytes, got ${signature.length}`,
|
|
98
172
|
});
|
|
99
173
|
}
|
|
100
174
|
return signature;
|
|
101
175
|
}
|
|
102
176
|
catch (error) {
|
|
103
|
-
// Re-throw SignerError as-is
|
|
177
|
+
// Re-throw SignerError as-is (from request())
|
|
104
178
|
if (error instanceof Error && error.name === 'SignerError') {
|
|
105
179
|
throw error;
|
|
106
180
|
}
|
|
107
|
-
|
|
108
|
-
// GCP SDK errors
|
|
109
|
-
const gcpError = error;
|
|
110
|
-
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
111
|
-
cause: error,
|
|
112
|
-
message: `GCP KMS Sign operation failed: ${gcpError.message || error.message}`,
|
|
113
|
-
status: gcpError.code,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
181
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
117
182
|
cause: error,
|
|
118
183
|
message: 'GCP KMS Sign operation failed',
|
|
119
184
|
});
|
|
@@ -165,8 +230,8 @@ export class GcpKmsSigner {
|
|
|
165
230
|
*/
|
|
166
231
|
async isAvailable() {
|
|
167
232
|
try {
|
|
168
|
-
const
|
|
169
|
-
|
|
233
|
+
const publicKey = await this.request(this.buildResourceUrl('/publicKey'), {
|
|
234
|
+
method: 'GET',
|
|
170
235
|
});
|
|
171
236
|
if (!publicKey) {
|
|
172
237
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcp-kms-signer.js","sourceRoot":"","sources":["../src/gcp-kms-signer.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"gcp-kms-signer.js","sourceRoot":"","sources":["../src/gcp-kms-signer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/keychain-gcp-kms",
|
|
3
3
|
"author": "Solana Foundation",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"description": "Google Cloud KMS-based signer for Solana transactions using EdDSA (Ed25519)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "https://github.com/solana-foundation/solana-keychain",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"src"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"@solana/keychain-core": "
|
|
32
|
+
"google-auth-library": "^10.6.2",
|
|
33
|
+
"@solana/keychain-core": "1.1.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@solana/addresses": ">=6.0.1",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@solana-program/memo": "^0.11.0",
|
|
47
47
|
"@solana/kit": "^6.0.1",
|
|
48
48
|
"dotenv": "^17.2.3",
|
|
49
|
-
"@solana/keychain-test-utils": "
|
|
49
|
+
"@solana/keychain-test-utils": "1.1.0"
|
|
50
50
|
},
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { address } from '@solana/addresses';
|
|
2
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import { assertIsSolanaSigner } from '@solana/keychain-core';
|
|
4
4
|
|
|
5
5
|
import { GcpKmsSigner } from '../gcp-kms-signer.js';
|
|
@@ -7,31 +7,75 @@ import type { GcpKmsSignerConfig } from '../types.js';
|
|
|
7
7
|
|
|
8
8
|
vi.mock('@solana/keychain-core', async importOriginal => {
|
|
9
9
|
const mod = await importOriginal<typeof import('@solana/keychain-core')>();
|
|
10
|
-
return {
|
|
10
|
+
return {
|
|
11
|
+
...mod,
|
|
12
|
+
assertSignatureValid: vi.fn(),
|
|
13
|
+
sanitizeRemoteErrorResponse:
|
|
14
|
+
mod.sanitizeRemoteErrorResponse ??
|
|
15
|
+
((text: string) =>
|
|
16
|
+
text
|
|
17
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, ' ')
|
|
18
|
+
.replace(/\s+/g, ' ')
|
|
19
|
+
.trim()
|
|
20
|
+
.slice(0, 256)),
|
|
21
|
+
};
|
|
11
22
|
});
|
|
12
23
|
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
24
|
+
const mockGetRequestHeaders = vi.fn();
|
|
25
|
+
const mockFetch = vi.fn();
|
|
26
|
+
const originalFetch = globalThis.fetch;
|
|
16
27
|
|
|
17
|
-
vi.mock('
|
|
28
|
+
vi.mock('google-auth-library', () => {
|
|
18
29
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
asymmetricSign = mockAsymmetricSign;
|
|
22
|
-
getPublicKey = mockGetPublicKey;
|
|
23
|
-
},
|
|
30
|
+
GoogleAuth: class {
|
|
31
|
+
getRequestHeaders = mockGetRequestHeaders;
|
|
24
32
|
},
|
|
25
33
|
};
|
|
26
34
|
});
|
|
27
35
|
|
|
36
|
+
function createJsonResponse(body: unknown, status = 200): Response {
|
|
37
|
+
return new Response(JSON.stringify(body), {
|
|
38
|
+
status,
|
|
39
|
+
headers: { 'content-type': 'application/json' },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getFetchCall(index: number): [string, RequestInit] {
|
|
44
|
+
return mockFetch.mock.calls[index] as [string, RequestInit];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function assertAuthorizedRequest(url: string, method: string, callIndex = 0): RequestInit {
|
|
48
|
+
const [calledUrl, init] = getFetchCall(callIndex);
|
|
49
|
+
expect(calledUrl).toBe(url);
|
|
50
|
+
expect(init.method).toBe(method);
|
|
51
|
+
|
|
52
|
+
const headers = new Headers(init.headers);
|
|
53
|
+
expect(headers.get('authorization')).toBe('Bearer test-token');
|
|
54
|
+
return init;
|
|
55
|
+
}
|
|
56
|
+
|
|
28
57
|
describe('GcpKmsSigner', () => {
|
|
29
58
|
const TEST_KEY_NAME =
|
|
30
59
|
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1';
|
|
60
|
+
const TEST_KEY_NAME_WITH_LEADING_SLASH = `/${TEST_KEY_NAME}`;
|
|
31
61
|
const TEST_PUBLIC_KEY = address('11111111111111111111111111111111');
|
|
62
|
+
const SIGN_ENDPOINT = `https://cloudkms.googleapis.com/v1/${TEST_KEY_NAME}:asymmetricSign`;
|
|
63
|
+
const PUBLIC_KEY_ENDPOINT = `https://cloudkms.googleapis.com/v1/${TEST_KEY_NAME}/publicKey`;
|
|
64
|
+
const TEST_SIGNATURE_BYTES = new Uint8Array(64).fill(0x42);
|
|
65
|
+
const TEST_SIGNATURE_BASE64 = Buffer.from(TEST_SIGNATURE_BYTES).toString('base64');
|
|
66
|
+
|
|
67
|
+
beforeAll(() => {
|
|
68
|
+
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
69
|
+
});
|
|
32
70
|
|
|
33
71
|
beforeEach(() => {
|
|
34
72
|
vi.clearAllMocks();
|
|
73
|
+
|
|
74
|
+
mockGetRequestHeaders.mockResolvedValue(new Headers({ authorization: 'Bearer test-token' }));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterAll(() => {
|
|
78
|
+
globalThis.fetch = originalFetch;
|
|
35
79
|
});
|
|
36
80
|
|
|
37
81
|
describe('create', () => {
|
|
@@ -88,6 +132,7 @@ describe('GcpKmsSigner', () => {
|
|
|
88
132
|
});
|
|
89
133
|
}).toThrow('Missing required publicKey field');
|
|
90
134
|
});
|
|
135
|
+
|
|
91
136
|
it('should throw error for invalid public key', () => {
|
|
92
137
|
expect(() => {
|
|
93
138
|
new GcpKmsSigner({
|
|
@@ -97,6 +142,39 @@ describe('GcpKmsSigner', () => {
|
|
|
97
142
|
}).toThrow('Invalid Solana public key format');
|
|
98
143
|
});
|
|
99
144
|
|
|
145
|
+
it('should throw error for invalid keyName format', () => {
|
|
146
|
+
const invalidKeyNames = [
|
|
147
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1#',
|
|
148
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/1?',
|
|
149
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key/cryptoKeyVersions/%31',
|
|
150
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key//cryptoKeyVersions/1',
|
|
151
|
+
'projects/test-project/locations/us-east1/keyRings/test-ring/cryptoKeys/test-key',
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
for (const keyName of invalidKeyNames) {
|
|
155
|
+
expect(() => {
|
|
156
|
+
new GcpKmsSigner({
|
|
157
|
+
keyName,
|
|
158
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
159
|
+
});
|
|
160
|
+
}).toThrow('Invalid GCP KMS keyName format');
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should canonicalize leading slashes in keyName', async () => {
|
|
165
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
166
|
+
|
|
167
|
+
const signer = new GcpKmsSigner({
|
|
168
|
+
keyName: TEST_KEY_NAME_WITH_LEADING_SLASH,
|
|
169
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
await signer.signMessages([{ content: new Uint8Array([1, 2, 3]), signatures: {} }]);
|
|
173
|
+
|
|
174
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
175
|
+
assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
176
|
+
});
|
|
177
|
+
|
|
100
178
|
it('should validate requestDelayMs', () => {
|
|
101
179
|
expect(() => {
|
|
102
180
|
new GcpKmsSigner({
|
|
@@ -124,11 +202,7 @@ describe('GcpKmsSigner', () => {
|
|
|
124
202
|
|
|
125
203
|
describe('signMessages', () => {
|
|
126
204
|
it('should sign a message successfully', async () => {
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
130
|
-
},
|
|
131
|
-
]);
|
|
205
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
132
206
|
|
|
133
207
|
const signer = new GcpKmsSigner({
|
|
134
208
|
keyName: TEST_KEY_NAME,
|
|
@@ -143,19 +217,40 @@ describe('GcpKmsSigner', () => {
|
|
|
143
217
|
|
|
144
218
|
expect(result).toHaveLength(1);
|
|
145
219
|
expect(result[0]?.[signer.address]).toBeDefined();
|
|
146
|
-
expect(
|
|
147
|
-
expect(
|
|
148
|
-
|
|
149
|
-
|
|
220
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
221
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
222
|
+
|
|
223
|
+
const init = assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
224
|
+
const headers = new Headers(init.headers);
|
|
225
|
+
expect(headers.get('content-type')).toBe('application/json');
|
|
226
|
+
expect(init.body).toBe(
|
|
227
|
+
JSON.stringify({
|
|
228
|
+
data: Buffer.from(message.content).toString('base64'),
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should build sign URL without fragments or queries for valid keyName', async () => {
|
|
234
|
+
const signer = new GcpKmsSigner({
|
|
235
|
+
keyName: TEST_KEY_NAME,
|
|
236
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
150
237
|
});
|
|
238
|
+
|
|
239
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
240
|
+
|
|
241
|
+
await signer.signMessages([{ content: new Uint8Array([1, 2, 3, 4]), signatures: {} }]);
|
|
242
|
+
|
|
243
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(SIGN_ENDPOINT);
|
|
244
|
+
const [calledUrl] = getFetchCall(0);
|
|
245
|
+
expect(calledUrl).toBe(SIGN_ENDPOINT);
|
|
246
|
+
expect(calledUrl).not.toContain('#');
|
|
247
|
+
expect(calledUrl).not.toContain('?');
|
|
151
248
|
});
|
|
152
249
|
|
|
153
250
|
it('should handle multiple messages with delay', async () => {
|
|
154
|
-
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
},
|
|
158
|
-
]);
|
|
251
|
+
mockFetch.mockImplementation(() =>
|
|
252
|
+
Promise.resolve(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 })),
|
|
253
|
+
);
|
|
159
254
|
|
|
160
255
|
const signer = new GcpKmsSigner({
|
|
161
256
|
keyName: TEST_KEY_NAME,
|
|
@@ -174,17 +269,13 @@ describe('GcpKmsSigner', () => {
|
|
|
174
269
|
const endTime = Date.now();
|
|
175
270
|
|
|
176
271
|
expect(result).toHaveLength(3);
|
|
177
|
-
expect(
|
|
178
|
-
// Should have some delay (at least 15ms for 2 delays of 10ms each)
|
|
272
|
+
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
179
273
|
expect(endTime - startTime).toBeGreaterThanOrEqual(15);
|
|
180
274
|
});
|
|
181
275
|
|
|
182
276
|
it('should throw error on invalid signature length', async () => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
signature: new Uint8Array(32), // Wrong length
|
|
186
|
-
},
|
|
187
|
-
]);
|
|
277
|
+
const shortSignature = Buffer.from(new Uint8Array(32).fill(0x42)).toString('base64');
|
|
278
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: shortSignature }));
|
|
188
279
|
|
|
189
280
|
const signer = new GcpKmsSigner({
|
|
190
281
|
keyName: TEST_KEY_NAME,
|
|
@@ -197,7 +288,7 @@ describe('GcpKmsSigner', () => {
|
|
|
197
288
|
});
|
|
198
289
|
|
|
199
290
|
it('should throw error on missing signature', async () => {
|
|
200
|
-
|
|
291
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
201
292
|
|
|
202
293
|
const signer = new GcpKmsSigner({
|
|
203
294
|
keyName: TEST_KEY_NAME,
|
|
@@ -210,9 +301,16 @@ describe('GcpKmsSigner', () => {
|
|
|
210
301
|
});
|
|
211
302
|
|
|
212
303
|
it('should handle GCP KMS API errors', async () => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
304
|
+
mockFetch.mockResolvedValue(
|
|
305
|
+
createJsonResponse(
|
|
306
|
+
{
|
|
307
|
+
error: {
|
|
308
|
+
message: 'GCP Error',
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
403,
|
|
312
|
+
),
|
|
313
|
+
);
|
|
216
314
|
|
|
217
315
|
const signer = new GcpKmsSigner({
|
|
218
316
|
keyName: TEST_KEY_NAME,
|
|
@@ -221,17 +319,26 @@ describe('GcpKmsSigner', () => {
|
|
|
221
319
|
|
|
222
320
|
const message = { content: new Uint8Array([1, 2, 3, 4]), signatures: {} };
|
|
223
321
|
|
|
224
|
-
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS
|
|
322
|
+
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS API error: 403');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should handle network errors', async () => {
|
|
326
|
+
mockFetch.mockRejectedValue(new Error('Network error'));
|
|
327
|
+
|
|
328
|
+
const signer = new GcpKmsSigner({
|
|
329
|
+
keyName: TEST_KEY_NAME,
|
|
330
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const message = { content: new Uint8Array([1, 2, 3, 4]), signatures: {} };
|
|
334
|
+
|
|
335
|
+
await expect(signer.signMessages([message])).rejects.toThrow('GCP KMS network request failed');
|
|
225
336
|
});
|
|
226
337
|
});
|
|
227
338
|
|
|
228
339
|
describe('signTransactions', () => {
|
|
229
340
|
it('should sign a transaction successfully', async () => {
|
|
230
|
-
|
|
231
|
-
{
|
|
232
|
-
signature: new Uint8Array(64).fill(0x42),
|
|
233
|
-
},
|
|
234
|
-
]);
|
|
341
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 }));
|
|
235
342
|
|
|
236
343
|
const signer = new GcpKmsSigner({
|
|
237
344
|
keyName: TEST_KEY_NAME,
|
|
@@ -247,15 +354,15 @@ describe('GcpKmsSigner', () => {
|
|
|
247
354
|
|
|
248
355
|
expect(result).toHaveLength(1);
|
|
249
356
|
expect(result[0]).toHaveProperty(signer.address);
|
|
250
|
-
expect(
|
|
357
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
358
|
+
|
|
359
|
+
assertAuthorizedRequest(SIGN_ENDPOINT, 'POST');
|
|
251
360
|
});
|
|
252
361
|
|
|
253
362
|
it('should sign multiple transactions successfully', async () => {
|
|
254
|
-
|
|
255
|
-
{
|
|
256
|
-
|
|
257
|
-
},
|
|
258
|
-
]);
|
|
363
|
+
mockFetch.mockImplementation(() =>
|
|
364
|
+
Promise.resolve(createJsonResponse({ signature: TEST_SIGNATURE_BASE64 })),
|
|
365
|
+
);
|
|
259
366
|
|
|
260
367
|
const signer = new GcpKmsSigner({
|
|
261
368
|
keyName: TEST_KEY_NAME,
|
|
@@ -270,15 +377,12 @@ describe('GcpKmsSigner', () => {
|
|
|
270
377
|
const result = await signer.signTransactions(transactions);
|
|
271
378
|
|
|
272
379
|
expect(result).toHaveLength(2);
|
|
273
|
-
expect(
|
|
380
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
274
381
|
});
|
|
275
382
|
|
|
276
383
|
it('should throw error on invalid signature length', async () => {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
signature: new Uint8Array(32),
|
|
280
|
-
},
|
|
281
|
-
]);
|
|
384
|
+
const shortSignature = Buffer.from(new Uint8Array(32).fill(0x42)).toString('base64');
|
|
385
|
+
mockFetch.mockResolvedValue(createJsonResponse({ signature: shortSignature }));
|
|
282
386
|
|
|
283
387
|
const signer = new GcpKmsSigner({
|
|
284
388
|
keyName: TEST_KEY_NAME,
|
|
@@ -291,7 +395,7 @@ describe('GcpKmsSigner', () => {
|
|
|
291
395
|
});
|
|
292
396
|
|
|
293
397
|
it('should throw error on missing signature', async () => {
|
|
294
|
-
|
|
398
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
295
399
|
|
|
296
400
|
const signer = new GcpKmsSigner({
|
|
297
401
|
keyName: TEST_KEY_NAME,
|
|
@@ -304,9 +408,16 @@ describe('GcpKmsSigner', () => {
|
|
|
304
408
|
});
|
|
305
409
|
|
|
306
410
|
it('should handle GCP KMS API errors', async () => {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
411
|
+
mockFetch.mockResolvedValue(
|
|
412
|
+
createJsonResponse(
|
|
413
|
+
{
|
|
414
|
+
error: {
|
|
415
|
+
message: 'GCP Error',
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
403,
|
|
419
|
+
),
|
|
420
|
+
);
|
|
310
421
|
|
|
311
422
|
const signer = new GcpKmsSigner({
|
|
312
423
|
keyName: TEST_KEY_NAME,
|
|
@@ -315,20 +426,13 @@ describe('GcpKmsSigner', () => {
|
|
|
315
426
|
|
|
316
427
|
const transaction = { messageBytes: new Uint8Array([1, 2, 3, 4]), signatures: {} } as any;
|
|
317
428
|
|
|
318
|
-
await expect(signer.signTransactions([transaction])).rejects.toThrow(
|
|
319
|
-
'GCP KMS Sign operation failed: GCP Error',
|
|
320
|
-
);
|
|
429
|
+
await expect(signer.signTransactions([transaction])).rejects.toThrow('GCP KMS API error: 403');
|
|
321
430
|
});
|
|
322
431
|
});
|
|
323
432
|
|
|
324
433
|
describe('isAvailable', () => {
|
|
325
434
|
it('should return true for valid Ed25519 key', async () => {
|
|
326
|
-
|
|
327
|
-
{
|
|
328
|
-
name: TEST_KEY_NAME,
|
|
329
|
-
algorithm: 'EC_SIGN_ED25519',
|
|
330
|
-
},
|
|
331
|
-
]);
|
|
435
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'EC_SIGN_ED25519' }));
|
|
332
436
|
|
|
333
437
|
const signer = new GcpKmsSigner({
|
|
334
438
|
keyName: TEST_KEY_NAME,
|
|
@@ -338,15 +442,27 @@ describe('GcpKmsSigner', () => {
|
|
|
338
442
|
const available = await signer.isAvailable();
|
|
339
443
|
|
|
340
444
|
expect(available).toBe(true);
|
|
445
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
446
|
+
assertAuthorizedRequest(PUBLIC_KEY_ENDPOINT, 'GET');
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('should use canonical public key endpoint for valid key names', async () => {
|
|
450
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'EC_SIGN_ED25519' }));
|
|
451
|
+
|
|
452
|
+
const signer = new GcpKmsSigner({
|
|
453
|
+
keyName: TEST_KEY_NAME_WITH_LEADING_SLASH,
|
|
454
|
+
publicKey: TEST_PUBLIC_KEY,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
const available = await signer.isAvailable();
|
|
458
|
+
|
|
459
|
+
expect(available).toBe(true);
|
|
460
|
+
expect(mockGetRequestHeaders).toHaveBeenCalledWith(PUBLIC_KEY_ENDPOINT);
|
|
461
|
+
assertAuthorizedRequest(PUBLIC_KEY_ENDPOINT, 'GET');
|
|
341
462
|
});
|
|
342
463
|
|
|
343
464
|
it('should return false for wrong algorithm', async () => {
|
|
344
|
-
|
|
345
|
-
{
|
|
346
|
-
name: TEST_KEY_NAME,
|
|
347
|
-
algorithm: 'RSA_SIGN_PKCS1_2048_SHA256',
|
|
348
|
-
},
|
|
349
|
-
]);
|
|
465
|
+
mockFetch.mockResolvedValue(createJsonResponse({ algorithm: 'RSA_SIGN_PKCS1_2048_SHA256' }));
|
|
350
466
|
|
|
351
467
|
const signer = new GcpKmsSigner({
|
|
352
468
|
keyName: TEST_KEY_NAME,
|
|
@@ -359,7 +475,7 @@ describe('GcpKmsSigner', () => {
|
|
|
359
475
|
});
|
|
360
476
|
|
|
361
477
|
it('should return false for missing public key response', async () => {
|
|
362
|
-
|
|
478
|
+
mockFetch.mockResolvedValue(createJsonResponse({}));
|
|
363
479
|
|
|
364
480
|
const signer = new GcpKmsSigner({
|
|
365
481
|
keyName: TEST_KEY_NAME,
|
|
@@ -371,8 +487,17 @@ describe('GcpKmsSigner', () => {
|
|
|
371
487
|
expect(available).toBe(false);
|
|
372
488
|
});
|
|
373
489
|
|
|
374
|
-
it('should return false on error', async () => {
|
|
375
|
-
|
|
490
|
+
it('should return false on API error', async () => {
|
|
491
|
+
mockFetch.mockResolvedValue(
|
|
492
|
+
createJsonResponse(
|
|
493
|
+
{
|
|
494
|
+
error: {
|
|
495
|
+
message: 'Forbidden',
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
403,
|
|
499
|
+
),
|
|
500
|
+
);
|
|
376
501
|
|
|
377
502
|
const signer = new GcpKmsSigner({
|
|
378
503
|
keyName: TEST_KEY_NAME,
|
package/src/gcp-kms-signer.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { v1 } from '@google-cloud/kms';
|
|
2
1
|
import { Address, assertIsAddress } from '@solana/addresses';
|
|
3
2
|
import {
|
|
4
3
|
assertSignatureValid,
|
|
5
4
|
createSignatureDictionary,
|
|
5
|
+
sanitizeRemoteErrorResponse,
|
|
6
6
|
SignerErrorCode,
|
|
7
7
|
SolanaSigner,
|
|
8
8
|
throwSignerError,
|
|
@@ -10,9 +10,28 @@ import {
|
|
|
10
10
|
import { SignatureBytes } from '@solana/keys';
|
|
11
11
|
import { SignableMessage, SignatureDictionary } from '@solana/signers';
|
|
12
12
|
import { Transaction, TransactionWithinSizeLimit, TransactionWithLifetime } from '@solana/transactions';
|
|
13
|
+
import { GoogleAuth } from 'google-auth-library';
|
|
13
14
|
|
|
14
15
|
import type { GcpKmsSignerConfig } from './types.js';
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Create a Google Cloud KMS-backed signer.
|
|
19
|
+
*
|
|
20
|
+
* @throws {SignerError} `SIGNER_CONFIG_ERROR` when required config is missing or invalid.
|
|
21
|
+
*/
|
|
22
|
+
const CLOUD_KMS_BASE_URL = 'https://cloudkms.googleapis.com/v1';
|
|
23
|
+
const CLOUD_KMS_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
|
|
24
|
+
const ED25519_SIGNATURE_LENGTH = 64;
|
|
25
|
+
const GCP_KMS_KEY_NAME_PATTERN =
|
|
26
|
+
/^projects\/[A-Za-z0-9._-]+\/locations\/[A-Za-z0-9._-]+\/keyRings\/[A-Za-z0-9._-]+\/cryptoKeys\/[A-Za-z0-9._-]+\/cryptoKeyVersions\/[A-Za-z0-9._-]+$/;
|
|
27
|
+
|
|
28
|
+
type AsymmetricSignResponse = {
|
|
29
|
+
signature?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type PublicKeyResponse = {
|
|
33
|
+
algorithm?: string;
|
|
34
|
+
};
|
|
16
35
|
export function createGcpKmsSigner<TAddress extends string = string>(
|
|
17
36
|
config: GcpKmsSignerConfig,
|
|
18
37
|
): SolanaSigner<TAddress> {
|
|
@@ -40,7 +59,8 @@ export function createGcpKmsSigner<TAddress extends string = string>(
|
|
|
40
59
|
export class GcpKmsSigner<TAddress extends string = string> implements SolanaSigner<TAddress> {
|
|
41
60
|
readonly address: Address<TAddress>;
|
|
42
61
|
private readonly keyName: string;
|
|
43
|
-
private readonly
|
|
62
|
+
private readonly keyNamePathSegments: readonly string[];
|
|
63
|
+
private readonly auth: GoogleAuth;
|
|
44
64
|
private readonly requestDelayMs: number;
|
|
45
65
|
|
|
46
66
|
/** @deprecated Use `createGcpKmsSigner()` instead. */
|
|
@@ -72,10 +92,85 @@ export class GcpKmsSigner<TAddress extends string = string> implements SolanaSig
|
|
|
72
92
|
});
|
|
73
93
|
}
|
|
74
94
|
|
|
75
|
-
this.keyName = config.keyName;
|
|
95
|
+
this.keyName = this.normalizeKeyName(config.keyName);
|
|
96
|
+
this.keyNamePathSegments = this.keyName.split('/');
|
|
76
97
|
this.requestDelayMs = config.requestDelayMs || 0;
|
|
77
98
|
this.validateRequestDelayMs(this.requestDelayMs);
|
|
78
|
-
this.
|
|
99
|
+
this.auth = new GoogleAuth({ scopes: [CLOUD_KMS_SCOPE] });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private normalizeKeyName(keyName: string): string {
|
|
103
|
+
const canonicalKeyName = keyName.replace(/^\/+/, '');
|
|
104
|
+
|
|
105
|
+
if (/\/{2,}/.test(canonicalKeyName) || /[#?%]/.test(canonicalKeyName)) {
|
|
106
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
107
|
+
message: 'Invalid GCP KMS keyName format',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!GCP_KMS_KEY_NAME_PATTERN.test(canonicalKeyName)) {
|
|
112
|
+
throwSignerError(SignerErrorCode.CONFIG_ERROR, {
|
|
113
|
+
message: 'Invalid GCP KMS keyName format',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return canonicalKeyName;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private buildResourceUrl(suffix: ':asymmetricSign' | '/publicKey'): string {
|
|
121
|
+
const url = new URL(`${CLOUD_KMS_BASE_URL}/`);
|
|
122
|
+
const basePathSegments = url.pathname.split('/').filter(Boolean);
|
|
123
|
+
url.pathname = `/${[...basePathSegments, ...this.keyNamePathSegments].join('/')}${suffix}`;
|
|
124
|
+
return url.toString();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private async authorizedFetch(url: string, init: RequestInit): Promise<Response> {
|
|
128
|
+
const authHeaders = await this.auth.getRequestHeaders(url);
|
|
129
|
+
const headers = new Headers(init.headers);
|
|
130
|
+
|
|
131
|
+
authHeaders.forEach((value, key) => {
|
|
132
|
+
headers.set(key, value);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (init.body && !headers.has('content-type')) {
|
|
136
|
+
headers.set('content-type', 'application/json');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return await fetch(url, { ...init, headers });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async request<TResponse>(url: string, init: RequestInit): Promise<TResponse> {
|
|
143
|
+
let response: Response;
|
|
144
|
+
try {
|
|
145
|
+
response = await this.authorizedFetch(url, init);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throwSignerError(SignerErrorCode.HTTP_ERROR, {
|
|
148
|
+
cause: error,
|
|
149
|
+
message: 'GCP KMS network request failed',
|
|
150
|
+
url,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
const errorText = await response.text().catch(() => 'Failed to read error response');
|
|
156
|
+
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
157
|
+
message: `GCP KMS API error: ${response.status}`,
|
|
158
|
+
response: sanitizeRemoteErrorResponse(errorText),
|
|
159
|
+
status: response.status,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let payload: TResponse;
|
|
164
|
+
try {
|
|
165
|
+
payload = (await response.json()) as TResponse;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throwSignerError(SignerErrorCode.PARSING_ERROR, {
|
|
168
|
+
cause: error,
|
|
169
|
+
message: 'Failed to parse GCP KMS response',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return payload;
|
|
79
174
|
}
|
|
80
175
|
|
|
81
176
|
/**
|
|
@@ -108,10 +203,11 @@ export class GcpKmsSigner<TAddress extends string = string> implements SolanaSig
|
|
|
108
203
|
*/
|
|
109
204
|
private async signBytes(messageBytes: Uint8Array): Promise<SignatureBytes> {
|
|
110
205
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
206
|
+
const response = await this.request<AsymmetricSignResponse>(this.buildResourceUrl(':asymmetricSign'), {
|
|
207
|
+
body: JSON.stringify({
|
|
208
|
+
data: Buffer.from(messageBytes).toString('base64'),
|
|
209
|
+
}),
|
|
210
|
+
method: 'POST',
|
|
115
211
|
});
|
|
116
212
|
|
|
117
213
|
if (!response.signature) {
|
|
@@ -121,29 +217,20 @@ export class GcpKmsSigner<TAddress extends string = string> implements SolanaSig
|
|
|
121
217
|
}
|
|
122
218
|
|
|
123
219
|
// Ed25519 signatures are 64 bytes
|
|
124
|
-
const signature = response.signature
|
|
125
|
-
if (signature.length !==
|
|
220
|
+
const signature = new Uint8Array(Buffer.from(response.signature, 'base64'));
|
|
221
|
+
if (signature.length !== ED25519_SIGNATURE_LENGTH) {
|
|
126
222
|
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
127
|
-
message: `Invalid signature length: expected
|
|
223
|
+
message: `Invalid signature length: expected ${ED25519_SIGNATURE_LENGTH} bytes, got ${signature.length}`,
|
|
128
224
|
});
|
|
129
225
|
}
|
|
130
226
|
|
|
131
227
|
return signature as SignatureBytes;
|
|
132
228
|
} catch (error: unknown) {
|
|
133
|
-
// Re-throw SignerError as-is
|
|
229
|
+
// Re-throw SignerError as-is (from request())
|
|
134
230
|
if (error instanceof Error && error.name === 'SignerError') {
|
|
135
231
|
throw error;
|
|
136
232
|
}
|
|
137
|
-
|
|
138
|
-
// GCP SDK errors
|
|
139
|
-
const gcpError = error as { code?: number; message?: string };
|
|
140
|
-
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
141
|
-
cause: error,
|
|
142
|
-
message: `GCP KMS Sign operation failed: ${gcpError.message || error.message}`,
|
|
143
|
-
status: gcpError.code,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
throwSignerError(SignerErrorCode.REMOTE_API_ERROR, {
|
|
233
|
+
throwSignerError(SignerErrorCode.SIGNING_FAILED, {
|
|
147
234
|
cause: error,
|
|
148
235
|
message: 'GCP KMS Sign operation failed',
|
|
149
236
|
});
|
|
@@ -205,8 +292,8 @@ export class GcpKmsSigner<TAddress extends string = string> implements SolanaSig
|
|
|
205
292
|
*/
|
|
206
293
|
async isAvailable(): Promise<boolean> {
|
|
207
294
|
try {
|
|
208
|
-
const
|
|
209
|
-
|
|
295
|
+
const publicKey = await this.request<PublicKeyResponse>(this.buildResourceUrl('/publicKey'), {
|
|
296
|
+
method: 'GET',
|
|
210
297
|
});
|
|
211
298
|
|
|
212
299
|
if (!publicKey) {
|