@acurast/cli
Version:
A cli to interact with the Acurast Cloud.
244 lines • 11.1 kB
JavaScript
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