UNPKG

@acurast/cli

Version:

A cli to interact with the Acurast Cloud.

244 lines 11.1 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import pkg from 'elliptic'; const { ec } = pkg; import * as crypto from 'crypto'; import { getProcessorEncryptionKey } from './utils.js'; import { AcurastService } from './acurastService.js'; import { LocalStorage } from '../../util/LocalStorage.js'; // Usage example const localStorage = new LocalStorage(); export class JobEnvironmentService { constructor() { } keyStorageId(type, curve) { return curve === 'p256' && localStorage.getItem(type) ? type // backwards compatiblity : `${type}_${curve}`; } getPublicKey(curve) { var _a; return ((_a = localStorage.getItem(this.keyStorageId('publicKey', curve))) !== null && _a !== void 0 ? _a : undefined); } setPublicKey(key, curve) { localStorage.setItem(this.keyStorageId('publicKey', curve), key); } getPrivateKey(curve) { var _a; return ((_a = localStorage.getItem(this.keyStorageId('privateKey', curve))) !== null && _a !== void 0 ? _a : undefined); } setPrivateKey(key, curve) { localStorage.setItem(this.keyStorageId('privateKey', curve), key); } generateSharedSecret(processorPublicKeyHex, curve) { return __awaiter(this, void 0, void 0, function* () { const EC = new ec(curve); let keyPair; // Check if a private key exists in local storage const storedPrivateKeyHex = this.getPrivateKey(curve); if (storedPrivateKeyHex) { // Use the existing private key keyPair = EC.keyFromPrivate(storedPrivateKeyHex, 'hex'); } else { // Generate a new key pair keyPair = EC.genKeyPair(); // Store the new private key this.setPrivateKey(keyPair.getPrivate('hex'), curve); // store the compressed public key this.setPublicKey(keyPair.getPublic(true, 'hex'), curve); } const processorKey = EC.keyFromPublic(processorPublicKeyHex, 'hex'); // Compute the shared secret ECDH const sharedSecret = keyPair.derive(processorKey.getPublic()); // Convert the shared secret to a hex string (with proper padding) return Buffer.from(sharedSecret.toArray()).toString('hex'); }); } generateSharedKey(processorPublicKeyHex, curve) { return __awaiter(this, void 0, void 0, function* () { const sharedSecret = Buffer.from(yield this.generateSharedSecret(processorPublicKeyHex, curve), 'hex'); const sharedSecretSalt = Buffer.alloc(16); //empty 16 byte array for secred salt const EC = new ec(curve); let keyPair; // Check if a private key exists in local storage const storedPrivateKeyHex = this.getPrivateKey(curve); if (storedPrivateKeyHex) { // Use the existing private key keyPair = EC.keyFromPrivate(storedPrivateKeyHex, 'hex'); } else { // Generate a new key pair keyPair = EC.genKeyPair(); // Store the new private key this.setPrivateKey(keyPair.getPrivate('hex'), curve); // store the compressed public key this.setPublicKey(keyPair.getPublic(true, 'hex'), curve); } const publicKey = Buffer.from(keyPair.getPublic(true, 'hex'), 'hex'); const processorPublicKey = Buffer.from(processorPublicKeyHex, 'hex'); // Sort the public keys const publicKeys = [publicKey, processorPublicKey].sort((a, b) => { if (a.length !== b.length) { return a.length - b.length; } else { for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return a[i] - b[i]; } } return 0; } }); const sharedCurveName = curve === 'p256' ? 'secp256r1' : curve === 'secp256k1' ? 'secp256k1' : ''; const info = Buffer.concat([ Buffer.from(`ECDH ${sharedCurveName} AES-256-GCM-SIV`, 'utf-8'), ...publicKeys, ]); const derivedKey = yield this.hkdf(sharedSecret, sharedSecretSalt, info, 32); return Buffer.from(derivedKey); }); } hkdf(keyMaterial, salt, info, length) { return __awaiter(this, void 0, void 0, function* () { const key = yield crypto.subtle.importKey('raw', keyMaterial, { name: 'HKDF' }, false, ['deriveBits']); return yield crypto.subtle.deriveBits({ name: 'HKDF', salt: salt, info: info, hash: 'SHA-256', }, key, length * 8); }); } encrypt(data, key) { const iv = crypto.randomBytes(12); // iv for AES-GCM should be 12 bytes const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); return { ciphertext: encrypted, iv: iv.toString('hex'), authTag: cipher.getAuthTag().toString('hex'), }; } processEncryptedHex(hex) { hex = hex.replace('0x', ''); //slice first 12 bytes for iv, last 16 bytes for authTag const iv = hex.substring(0, 24); // First 12 bytes const ciphertext = hex.substring(24, hex.length - 32); // Middle portion const authTag = hex.substring(hex.length - 32); // Last 16 bytes return { ciphertext: ciphertext, iv: iv, authTag: authTag, }; } decrypt(data, key) { const decipher = crypto.createDecipheriv('aes-256-gcm', key, Buffer.from(data.iv, 'hex')); decipher.setAuthTag(Buffer.from(data.authTag, 'hex')); let decrypted = decipher.update(data.ciphertext, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } setEnvironmentVariables(keyring, assignment, jobId, jobEnvironmentVariables) { return __awaiter(this, void 0, void 0, function* () { const processorEncryptionKey = getProcessorEncryptionKey(assignment); if (processorEncryptionKey !== undefined) { const sharedKey = yield this.generateSharedKey(processorEncryptionKey.publicKey, processorEncryptionKey.curve); //encrypt environment variables const encryptedEnvironment = jobEnvironmentVariables.map((envVar) => ({ key: envVar.key, encryptedValue: this.encrypt(envVar.value, sharedKey), })); const publicKey = this.getPublicKey(processorEncryptionKey.curve); if (publicKey !== undefined) { const jobEnvironment = { publicKey, variables: encryptedEnvironment, }; return this.setEnvironment(keyring, jobId, jobEnvironment); } return undefined; } return undefined; }); } setEnvironment(keyring, jobId, jobEnvironment) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const acurast = new AcurastService(); const hash = yield acurast .setEnvironment(keyring, jobId, jobEnvironment) .then((v) => v.toString()) .catch(reject); if (hash) { resolve({ hash, }); } } catch (e) { reject(e); } })); }); } setEnvironmentVariablesMulti(keyring, assignments, jobId, jobEnvironmentVariables) { return __awaiter(this, void 0, void 0, function* () { let jobEnvironments = []; for (let assignment of assignments) { const processorEncryptionKey = getProcessorEncryptionKey(assignment); if (processorEncryptionKey !== undefined) { const sharedKey = yield this.generateSharedKey(processorEncryptionKey.publicKey, processorEncryptionKey.curve); //encrypt environment variables const encryptedEnvironment = jobEnvironmentVariables.map((envVar) => ({ key: envVar.key, encryptedValue: this.encrypt(envVar.value, sharedKey), })); const publicKey = this.getPublicKey(processorEncryptionKey.curve); if (publicKey !== undefined) { const jobEnvironment = { publicKey, variables: encryptedEnvironment, }; jobEnvironments.push({ processor: assignment.processor, jobEnvironment: jobEnvironment, }); } } } return this.setEnvironments(keyring, jobId, jobEnvironments); }); } setEnvironments(keyring, jobId, jobEnvironments) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const acurast = new AcurastService(); const hash = yield acurast .setEnvironments(keyring, jobId, jobEnvironments) .then((v) => v.toString()) .catch(reject); if (hash) { resolve({ hash, }); } } catch (e) { reject(e); } })); }); } } //# sourceMappingURL=jobEnvironmentService.js.map