@rnaga/wp-node
Version:
👉 **[View Full Documentation at rnaga.github.io/wp-node →](https://rnaga.github.io/wp-node/)**
173 lines (172 loc) • 7.23 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashEquals = exports.sodiumBase642bin = exports.sodiumBin2Base64 = exports.sodiumCryptoGenerichash = exports.SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = exports.SODIUM_BASE64_VARIANT_URLSAFE = exports.SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = exports.SODIUM_BASE64_VARIANT_ORIGINAL = void 0;
const crypto = __importStar(require("crypto"));
const sodium = __importStar(require("sodium-native"));
// Constants for base64 variants (matching PHP sodium constants)
const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
exports.SODIUM_BASE64_VARIANT_ORIGINAL = SODIUM_BASE64_VARIANT_ORIGINAL;
const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
exports.SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING;
const SODIUM_BASE64_VARIANT_URLSAFE = 5;
exports.SODIUM_BASE64_VARIANT_URLSAFE = SODIUM_BASE64_VARIANT_URLSAFE;
const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
exports.SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING;
/**
* TypeScript equivalent of PHP's sodium_crypto_generichash()
*
* @param message - The message to hash
* @param key - Optional key for keyed hashing
* @param length - Output length in bytes (default: 32, min: 16, max: 64)
* @returns Buffer containing the hash
*/
const sodiumCryptoGenerichash = (message, key, length = 32) => {
// Convert string inputs to Buffer
const messageBuffer = Buffer.isBuffer(message)
? message
: Buffer.from(message, "utf8");
const keyBuffer = key
? Buffer.isBuffer(key)
? key
: Buffer.from(key, "utf8")
: null;
// Validate length parameter
if (length < 16 || length > 64) {
throw new Error("Hash length must be between 16 and 64 bytes");
}
// Create output buffer
const output = Buffer.alloc(length);
// Compute hash using sodium-native
if (keyBuffer) {
sodium.crypto_generichash(output, messageBuffer, keyBuffer);
}
else {
sodium.crypto_generichash(output, messageBuffer);
}
return output;
};
exports.sodiumCryptoGenerichash = sodiumCryptoGenerichash;
/**
* TypeScript equivalent of PHP's sodium_bin2base64()
* Encodes binary data to base64
*
* @param data - Binary data to encode
* @param variant - Base64 variant (SODIUM_BASE64_VARIANT_ORIGINAL, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, SODIUM_BASE64_VARIANT_URLSAFE, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING)
* @returns Base64 encoded string
*/
const sodiumBin2Base64 = (data, variant = SODIUM_BASE64_VARIANT_ORIGINAL) => {
const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data, "binary");
switch (variant) {
case SODIUM_BASE64_VARIANT_ORIGINAL:
return dataBuffer.toString("base64");
case SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING:
return dataBuffer.toString("base64").replace(/=/g, "");
case SODIUM_BASE64_VARIANT_URLSAFE:
return dataBuffer
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_");
case SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING:
return dataBuffer
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
default:
throw new Error("Invalid base64 variant");
}
};
exports.sodiumBin2Base64 = sodiumBin2Base64;
/**
* Convert base64 string back to binary data
* @param base64 - Base64 encoded string
* @param variant - Base64 variant that was used for encoding
* @returns Buffer containing the decoded binary data
*/
const sodiumBase642bin = (base64, variant = SODIUM_BASE64_VARIANT_ORIGINAL) => {
let normalizedBase64 = base64;
switch (variant) {
case SODIUM_BASE64_VARIANT_ORIGINAL:
// Standard base64 with padding (default)
break;
case SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING:
// Standard base64 without padding - add padding back
while (normalizedBase64.length % 4 !== 0) {
normalizedBase64 += "=";
}
break;
case SODIUM_BASE64_VARIANT_URLSAFE:
// URL-safe base64 with padding - convert back to standard
normalizedBase64 = normalizedBase64.replace(/-/g, "+").replace(/_/g, "/");
break;
case SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING:
// URL-safe base64 without padding - convert and add padding
normalizedBase64 = normalizedBase64.replace(/-/g, "+").replace(/_/g, "/");
while (normalizedBase64.length % 4 !== 0) {
normalizedBase64 += "=";
}
break;
default:
throw new Error(`Invalid base64 variant: ${variant}`);
}
try {
return Buffer.from(normalizedBase64, "base64");
}
catch (error) {
throw new Error("Invalid base64 string");
}
};
exports.sodiumBase642bin = sodiumBase642bin;
/**
* TypeScript equivalent of PHP's hash_equals()
* Timing-safe string comparison to prevent timing attacks
*
* @param known - Known string (expected value)
* @param user - User-provided string to compare
* @returns true if strings are equal, false otherwise
*/
const hashEquals = (known, user) => {
// Convert to buffers for consistent comparison
const knownBuffer = Buffer.from(known, "utf8");
const userBuffer = Buffer.from(user, "utf8");
// Use Node.js crypto.timingSafeEqual for constant-time comparison
// First check if lengths are equal (this itself is constant time for same-length inputs)
if (knownBuffer.length !== userBuffer.length) {
return false;
}
return crypto.timingSafeEqual(knownBuffer, userBuffer);
};
exports.hashEquals = hashEquals;