blockintel-gate-sdk 0.4.5 → 0.4.7
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/index.cjs +104 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +104 -1
- package/dist/index.js.map +1 -1
- package/dist/pilot/index.cjs +72 -0
- package/dist/pilot/index.cjs.map +1 -1
- package/dist/pilot/index.js +72 -0
- package/dist/pilot/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1217,6 +1217,12 @@ async function handleSignCommand(command, originalClient, gateClient, options) {
|
|
|
1217
1217
|
if (options.mode === "dry-run") {
|
|
1218
1218
|
return await originalClient.send(new clientKms.SignCommand(command));
|
|
1219
1219
|
}
|
|
1220
|
+
const GATEWAY_STAGES = ["HARD_KMS_GATEWAY", "HARD_GCP_GATEWAY"];
|
|
1221
|
+
const currentStage = gateClient.heartbeatManager?.getAdoptionStage?.();
|
|
1222
|
+
if (currentStage && GATEWAY_STAGES.includes(currentStage)) {
|
|
1223
|
+
emitMetric(options.metricsSink, "sign_success_total", labels);
|
|
1224
|
+
return await signViaProxy(gateClient, decision, command, signerId);
|
|
1225
|
+
}
|
|
1220
1226
|
return await originalClient.send(new clientKms.SignCommand(command));
|
|
1221
1227
|
} catch (error) {
|
|
1222
1228
|
if (error instanceof BlockIntelBlockedError) {
|
|
@@ -1230,6 +1236,72 @@ async function handleSignCommand(command, originalClient, gateClient, options) {
|
|
|
1230
1236
|
throw error;
|
|
1231
1237
|
}
|
|
1232
1238
|
}
|
|
1239
|
+
async function signViaProxy(gateClient, decision, command, signerId) {
|
|
1240
|
+
const config = gateClient.config;
|
|
1241
|
+
const baseUrl = config?.baseUrl || config?.controlPlaneUrl;
|
|
1242
|
+
const tenantId = config?.tenantId;
|
|
1243
|
+
if (!baseUrl || !tenantId) {
|
|
1244
|
+
throw new Error("[Gate SDK] Cannot use signing proxy: baseUrl or tenantId not configured on GateClient");
|
|
1245
|
+
}
|
|
1246
|
+
const message = command.input?.Message ?? command.Message;
|
|
1247
|
+
if (!message) {
|
|
1248
|
+
throw new Error("[Gate SDK] SignCommand missing Message for proxy signing");
|
|
1249
|
+
}
|
|
1250
|
+
const messageBuffer = message instanceof Buffer ? message : Buffer.from(message);
|
|
1251
|
+
const messageBase64 = messageBuffer.toString("base64");
|
|
1252
|
+
const keyId = command.input?.KeyId ?? command.KeyId;
|
|
1253
|
+
if (!keyId) {
|
|
1254
|
+
throw new Error("[Gate SDK] SignCommand missing KeyId for proxy signing");
|
|
1255
|
+
}
|
|
1256
|
+
const signingAlgorithm = command.input?.SigningAlgorithm ?? command.SigningAlgorithm ?? "ECDSA_SHA_256";
|
|
1257
|
+
const messageType = command.input?.MessageType ?? command.MessageType ?? "RAW";
|
|
1258
|
+
const proxyUrl = `${baseUrl.replace("/defense", "")}/tenants/${tenantId}/defense/sign`;
|
|
1259
|
+
const headers = {
|
|
1260
|
+
"Content-Type": "application/json"
|
|
1261
|
+
};
|
|
1262
|
+
const authHeaders = gateClient.getAuthHeaders?.();
|
|
1263
|
+
if (authHeaders) {
|
|
1264
|
+
Object.assign(headers, authHeaders);
|
|
1265
|
+
} else {
|
|
1266
|
+
const auth = config?.auth;
|
|
1267
|
+
if (auth?.mode === "api_key" && auth?.apiKey) {
|
|
1268
|
+
headers["x-api-key"] = auth.apiKey;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
const jwt = gateClient.jwt || gateClient.config?.jwt;
|
|
1272
|
+
if (jwt) {
|
|
1273
|
+
headers["Authorization"] = `Bearer ${jwt}`;
|
|
1274
|
+
}
|
|
1275
|
+
const response = await fetch(proxyUrl, {
|
|
1276
|
+
method: "POST",
|
|
1277
|
+
headers,
|
|
1278
|
+
body: JSON.stringify({
|
|
1279
|
+
requestId: decision.decisionId || decision.requestId,
|
|
1280
|
+
decisionToken: decision.decisionToken,
|
|
1281
|
+
keyId,
|
|
1282
|
+
message: messageBase64,
|
|
1283
|
+
signingAlgorithm,
|
|
1284
|
+
messageType
|
|
1285
|
+
})
|
|
1286
|
+
});
|
|
1287
|
+
if (!response.ok) {
|
|
1288
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
1289
|
+
const code = errorBody?.error?.code || "SIGN_PROXY_FAILED";
|
|
1290
|
+
const msg = errorBody?.error?.message || `Signing proxy returned ${response.status}`;
|
|
1291
|
+
throw new Error(`[Gate SDK] ${code}: ${msg}`);
|
|
1292
|
+
}
|
|
1293
|
+
const result = await response.json();
|
|
1294
|
+
const data = result?.data;
|
|
1295
|
+
if (!data?.signature) {
|
|
1296
|
+
throw new Error("[Gate SDK] Signing proxy returned no signature");
|
|
1297
|
+
}
|
|
1298
|
+
return {
|
|
1299
|
+
Signature: Buffer.from(data.signature, "base64"),
|
|
1300
|
+
KeyId: data.keyId || keyId,
|
|
1301
|
+
SigningAlgorithm: data.signingAlgorithm || signingAlgorithm,
|
|
1302
|
+
$metadata: { httpStatusCode: 200 }
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1233
1305
|
|
|
1234
1306
|
// src/provenance/ProvenanceProvider.ts
|
|
1235
1307
|
var ProvenanceProvider = class {
|
|
@@ -2938,7 +3010,38 @@ var GcpKmsSigner = class {
|
|
|
2938
3010
|
if (!this.config.credentials) {
|
|
2939
3011
|
throw new Error("GCP credentials not configured");
|
|
2940
3012
|
}
|
|
2941
|
-
|
|
3013
|
+
const creds = typeof this.config.credentials === "string" ? JSON.parse(this.config.credentials) : this.config.credentials;
|
|
3014
|
+
if (!creds.client_email || !creds.private_key) {
|
|
3015
|
+
throw new Error("GCP credentials must contain client_email and private_key");
|
|
3016
|
+
}
|
|
3017
|
+
const crypto = await import('crypto');
|
|
3018
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3019
|
+
const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
|
|
3020
|
+
const payload = Buffer.from(JSON.stringify({
|
|
3021
|
+
iss: creds.client_email,
|
|
3022
|
+
scope: "https://www.googleapis.com/auth/cloudkms",
|
|
3023
|
+
aud: "https://oauth2.googleapis.com/token",
|
|
3024
|
+
iat: now,
|
|
3025
|
+
exp: now + 3600
|
|
3026
|
+
})).toString("base64url");
|
|
3027
|
+
const sigInput = `${header}.${payload}`;
|
|
3028
|
+
const sign = crypto.createSign("RSA-SHA256");
|
|
3029
|
+
sign.update(sigInput);
|
|
3030
|
+
const sig = sign.sign(creds.private_key, "base64url");
|
|
3031
|
+
const jwt = `${sigInput}.${sig}`;
|
|
3032
|
+
const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
|
|
3033
|
+
method: "POST",
|
|
3034
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
3035
|
+
body: `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`
|
|
3036
|
+
});
|
|
3037
|
+
if (!tokenResponse.ok) {
|
|
3038
|
+
const errText = await tokenResponse.text();
|
|
3039
|
+
throw new Error(`GCP SA token exchange failed: ${tokenResponse.status} ${errText}`);
|
|
3040
|
+
}
|
|
3041
|
+
const data = await tokenResponse.json();
|
|
3042
|
+
this.accessToken = data.access_token;
|
|
3043
|
+
this.tokenExpiry = Date.now() + data.expires_in * 1e3;
|
|
3044
|
+
return data.access_token;
|
|
2942
3045
|
}
|
|
2943
3046
|
}
|
|
2944
3047
|
/**
|