@praecise/tere
Version:
Trusted Execution Runtime Environment SDK
174 lines (173 loc) • 6.33 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TerePackager = void 0;
const crypto_1 = __importDefault(require("crypto"));
/**
* Utilities for packaging TERE scripts
*/
class TerePackager {
/**
* Create a TERE script from code and metadata
* @param options Packaging options
* @returns The compiled TERE binary as a Buffer
*/
static createScript(options) {
// Generate a unique ID if not provided
const scriptId = options.id || `script_${crypto_1.default.randomUUID ? crypto_1.default.randomUUID() : this.generateUUID()}`;
// Create metadata JSON
const metadata = {
id: scriptId,
name: options.name,
version: options.version,
timestamp: new Date().toISOString(),
author: options.author || '',
description: options.description || '',
functions: options.functions || [],
sha256: '' // Will be filled in later
};
// Convert code to Buffer
const codeBuffer = Buffer.from(options.code, 'utf8');
// Calculate SHA-256 hash of the code
const hash = crypto_1.default.createHash('sha256').update(codeBuffer).digest('hex');
metadata.sha256 = hash;
// Convert metadata to Buffer
const metadataJson = JSON.stringify(metadata);
const metadataBuffer = Buffer.from(metadataJson, 'utf8');
// Create metadata length Buffer (4 bytes, little-endian)
const metadataLengthBuffer = Buffer.alloc(4);
metadataLengthBuffer.writeUInt32LE(metadataBuffer.length, 0);
// Create magic header Buffer
const headerBuffer = Buffer.from(this.MAGIC_HEADER, 'utf8');
// Combine all Buffers
return Buffer.concat([
headerBuffer,
metadataLengthBuffer,
metadataBuffer,
codeBuffer
]);
}
/**
* Validate a TERE script
* @param script The TERE script to validate
* @returns True if the script is valid, false otherwise
*/
static validateScript(script) {
// Check minimum length
if (script.length < 13) {
return false;
}
// Check magic header
const header = script.toString('utf8', 0, 8);
if (header !== this.MAGIC_HEADER) {
return false;
}
// Get metadata length
const metadataLength = script.readUInt32LE(8);
// Check if script is long enough to contain metadata
if (script.length < 12 + metadataLength) {
return false;
}
// Get metadata
const metadataJson = script.toString('utf8', 12, 12 + metadataLength);
let metadata;
try {
metadata = JSON.parse(metadataJson);
}
catch (e) {
return false;
}
// Get code
const code = script.slice(12 + metadataLength);
// Verify hash if present
if (metadata.sha256) {
const calculatedHash = crypto_1.default.createHash('sha256').update(code).digest('hex');
if (calculatedHash !== metadata.sha256) {
return false;
}
}
return true;
}
/**
* Extract metadata from a TERE script
* @param script The TERE script to extract metadata from
* @returns The metadata as a ScriptMetadata object
*/
static extractMetadata(script) {
if (!this.validateScript(script)) {
throw new Error('Invalid TERE script');
}
// Get metadata length
const metadataLength = script.readUInt32LE(8);
// Get metadata
const metadataJson = script.toString('utf8', 12, 12 + metadataLength);
return JSON.parse(metadataJson);
}
/**
* Get the script ID from a TERE script
* @param script The TERE script to get the ID from
* @returns The script ID, or null if not found
*/
static getScriptId(script) {
try {
const metadata = this.extractMetadata(script);
return metadata.id || null;
}
catch (e) {
return null;
}
}
/**
* Generate a UUID (fallback for older Node.js versions)
* @returns A UUID string
*/
static generateUUID() {
// Simple UUID v4 implementation for older Node.js versions
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Update the functions list in a TERE script
* @param script The TERE script to update
* @param functions The updated list of exported functions
* @returns The updated TERE binary as a Buffer
*/
static updateFunctions(script, functions) {
if (!this.validateScript(script)) {
throw new Error('Invalid TERE script');
}
// Get metadata length
const metadataLength = script.readUInt32LE(8);
// Get metadata
const metadataJson = script.toString('utf8', 12, 12 + metadataLength);
const metadata = JSON.parse(metadataJson);
// Update functions
metadata.functions = functions;
// Get code
const code = script.slice(12 + metadataLength);
// Create updated metadata Buffer
const updatedMetadataJson = JSON.stringify(metadata);
const updatedMetadataBuffer = Buffer.from(updatedMetadataJson, 'utf8');
// Create updated metadata length Buffer
const updatedMetadataLengthBuffer = Buffer.alloc(4);
updatedMetadataLengthBuffer.writeUInt32LE(updatedMetadataBuffer.length, 0);
// Create magic header Buffer
const headerBuffer = Buffer.from(this.MAGIC_HEADER, 'utf8');
// Combine all Buffers
return Buffer.concat([
headerBuffer,
updatedMetadataLengthBuffer,
updatedMetadataBuffer,
code
]);
}
}
exports.TerePackager = TerePackager;
/**
* Magic header for TERE scripts
*/
TerePackager.MAGIC_HEADER = 'TERE0001';