@synet/credential
Version:
VC Credentials - Simple, Robust, Unit-based Verifiable Credentials service
84 lines (83 loc) • 3.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createId = createId;
exports.base64urlEncode = base64urlEncode;
exports.base64urlDecode = base64urlDecode;
const node_crypto_1 = require("node:crypto");
/**
* Generate a CUID2-like identifier using Node.js crypto
*
* This is a simplified, zero-dependency implementation of CUID2 concepts:
* - Uses native Node.js crypto instead of @noble/hashes
* - Maintains similar structure: letter + hash of (time + entropy + counter)
* - Provides collision-resistant, sortable, URL-safe IDs
*
* @param length - Length of the generated ID (default: 24)
* @returns A CUID2-like identifier string
*/
function createId(length = 24) {
// Start with a random letter (a-z)
const firstLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
// Create entropy components
const time = Date.now().toString(36);
const entropy = (0, node_crypto_1.randomBytes)(8).toString("hex");
const counter = Math.floor(Math.random() * 0xffffff).toString(36);
// Combine and hash
const input = `${time}${entropy}${counter}`;
const hash = (0, node_crypto_1.createHash)("sha3-512").update(input).digest("hex");
// Convert to base36 and take required length
const hashBigInt = BigInt(`0x${hash}`);
const base36Hash = hashBigInt.toString(36);
// Combine first letter with hash, ensuring we get the right length
return (firstLetter + base36Hash).substring(0, length);
}
/**
* Base64url encoding utilities (simplified)
*/
function base64urlEncode(data) {
try {
// Try Node.js Buffer first
const nodeBuffer = globalThis?.Buffer;
if (nodeBuffer && typeof nodeBuffer === "object" && "from" in nodeBuffer) {
return nodeBuffer
.from(data)
.toString("base64url");
}
// Fallback to browser btoa
const browserBtoa = globalThis?.btoa;
if (browserBtoa && typeof browserBtoa === "function") {
return browserBtoa(data)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
throw new Error("No base64 encoding available");
}
catch (error) {
throw new Error(`Base64 encoding failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
function base64urlDecode(data) {
try {
// Try Node.js Buffer first
const nodeBuffer = globalThis?.Buffer;
if (nodeBuffer && typeof nodeBuffer === "object" && "from" in nodeBuffer) {
return nodeBuffer
.from(data, "base64url")
.toString();
}
// Fallback to browser atob
const browserAtob = globalThis?.atob;
if (browserAtob && typeof browserAtob === "function") {
let base64 = data.replace(/-/g, "+").replace(/_/g, "/");
while (base64.length % 4) {
base64 += "=";
}
return browserAtob(base64);
}
throw new Error("No base64 decoding available");
}
catch (error) {
throw new Error(`Base64 decoding failed: ${error instanceof Error ? error.message : String(error)}`);
}
}