\x89PNG\r\n\x1a\n\x00\x00\x00\x0DIHDR\x00\x00\x00\x01\x00 \x00\x00\x01\x08\x06\x00\x00\x00\x1F\x15\xC4\x89\x00\x00\x00 \x0AIDATx\x9Ccb\x00\x00\x00\x06\x00\x03\x1A\x05\x9D\x00\x00 \x00\x00IEND\xAE\x42\x60\x82 www.csarite.com
KUJUNTI.ID MINISH3LL
Path : /var/www/html/infraai.ai/frontend/node_modules/selfsigned/
(S)h3ll Cr3at0r :
F!le Upl0ad :

B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H

Current File : /var/www/html/infraai.ai/frontend/node_modules/selfsigned/index.js


const { X509CertificateGenerator, X509Certificate, cryptoProvider,  X509ChainBuilder, BasicConstraintsExtension, KeyUsagesExtension, KeyUsageFlags, ExtendedKeyUsageExtension, ExtendedKeyUsage, SubjectAlternativeNameExtension, GeneralName } = require("@peculiar/x509");
const nodeCrypto = require("crypto");

// Use Node.js native webcrypto
const crypto = nodeCrypto.webcrypto;

// Patch global CryptoProvider to use Node.js crypto
cryptoProvider.set(crypto);

// a hexString is considered negative if it's most significant bit is 1
// because serial numbers use ones' complement notation
// this RFC in section 4.1.2.2 requires serial numbers to be positive
// http://www.ietf.org/rfc/rfc5280.txt
function toPositiveHex(hexString) {
  var mostSiginficativeHexAsInt = parseInt(hexString[0], 16);
  if (mostSiginficativeHexAsInt < 8) {
    return hexString;
  }

  mostSiginficativeHexAsInt -= 8;
  return mostSiginficativeHexAsInt.toString() + hexString.substring(1);
}

function getAlgorithmName(key) {
  switch (key) {
    case "sha256":
      return "SHA-256";
    case 'sha384':
      return "SHA-384";
    case 'sha512':
      return "SHA-512";
    default:
      return "SHA-1";
  }
}

function getSigningAlgorithm(hashKey, keyType) {
  const hashAlg = getAlgorithmName(hashKey);
  if (keyType === 'ec') {
    return {
      name: "ECDSA",
      hash: hashAlg
    };
  }
  return {
    name: "RSASSA-PKCS1-v1_5",
    hash: hashAlg
  };
}

function getKeyAlgorithm(options) {
  const keyType = options.keyType || 'rsa';
  const hashAlg = getAlgorithmName(options.algorithm || 'sha1');

  if (keyType === 'ec') {
    const curve = options.curve || 'P-256';
    return {
      name: "ECDSA",
      namedCurve: curve
    };
  }

  return {
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: options.keySize || 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: hashAlg
  };
}

// Build extensions array from options or use defaults
// Supports the old node-forge extension format for backwards compatibility
function buildExtensions(userExtensions, commonName) {
  if (!userExtensions || userExtensions.length === 0) {
    // Default extensions
    return [
      new BasicConstraintsExtension(false, undefined, true),
      new KeyUsagesExtension(KeyUsageFlags.digitalSignature | KeyUsageFlags.keyEncipherment, true),
      new ExtendedKeyUsageExtension([ExtendedKeyUsage.serverAuth, ExtendedKeyUsage.clientAuth], false),
      new SubjectAlternativeNameExtension([
        { type: 'dns', value: commonName },
        ...(commonName === 'localhost' ? [{ type: 'ip', value: '127.0.0.1' }] : [])
      ], false)
    ];
  }

  // Convert user extensions from node-forge format to @peculiar/x509 format
  const extensions = [];

  for (const ext of userExtensions) {
    const critical = ext.critical || false;

    switch (ext.name) {
      case 'basicConstraints':
        extensions.push(new BasicConstraintsExtension(
          ext.cA || false,
          ext.pathLenConstraint,
          critical
        ));
        break;

      case 'keyUsage':
        let flags = 0;
        if (ext.digitalSignature) flags |= KeyUsageFlags.digitalSignature;
        if (ext.nonRepudiation || ext.contentCommitment) flags |= KeyUsageFlags.nonRepudiation;
        if (ext.keyEncipherment) flags |= KeyUsageFlags.keyEncipherment;
        if (ext.dataEncipherment) flags |= KeyUsageFlags.dataEncipherment;
        if (ext.keyAgreement) flags |= KeyUsageFlags.keyAgreement;
        if (ext.keyCertSign) flags |= KeyUsageFlags.keyCertSign;
        if (ext.cRLSign) flags |= KeyUsageFlags.cRLSign;
        if (ext.encipherOnly) flags |= KeyUsageFlags.encipherOnly;
        if (ext.decipherOnly) flags |= KeyUsageFlags.decipherOnly;
        extensions.push(new KeyUsagesExtension(flags, critical));
        break;

      case 'extKeyUsage':
        const usages = [];
        if (ext.serverAuth) usages.push(ExtendedKeyUsage.serverAuth);
        if (ext.clientAuth) usages.push(ExtendedKeyUsage.clientAuth);
        if (ext.codeSigning) usages.push(ExtendedKeyUsage.codeSigning);
        if (ext.emailProtection) usages.push(ExtendedKeyUsage.emailProtection);
        if (ext.timeStamping) usages.push(ExtendedKeyUsage.timeStamping);
        extensions.push(new ExtendedKeyUsageExtension(usages, critical));
        break;

      case 'subjectAltName':
        const altNames = (ext.altNames || []).map(alt => {
          // node-forge type values:
          // 1 = email (rfc822Name)
          // 2 = DNS
          // 6 = URI
          // 7 = IP
          switch (alt.type) {
            case 1: // email
              return { type: 'email', value: alt.value };
            case 2: // DNS
              return { type: 'dns', value: alt.value };
            case 6: // URI
              return { type: 'url', value: alt.value };
            case 7: // IP
              return { type: 'ip', value: alt.ip || alt.value };
            default:
              // Try to infer type from properties
              if (alt.ip) return { type: 'ip', value: alt.ip };
              if (alt.dns) return { type: 'dns', value: alt.dns };
              if (alt.email) return { type: 'email', value: alt.email };
              if (alt.uri || alt.url) return { type: 'url', value: alt.uri || alt.url };
              return { type: 'dns', value: alt.value };
          }
        });
        extensions.push(new SubjectAlternativeNameExtension(altNames, critical));
        break;

      default:
        // Skip unknown extensions with a warning
        console.warn(`Unknown extension "${ext.name}" ignored`);
    }
  }

  return extensions;
}

// Convert attributes from node-forge format to X509 name format
function convertAttributes(attrs) {
  const nameMap = {
    'commonName': 'CN',
    'countryName': 'C',
    'ST': 'ST',
    'localityName': 'L',
    'organizationName': 'O',
    'OU': 'OU'
  };

  return attrs.map(attr => {
    const key = attr.name || attr.shortName;
    const oid = nameMap[key] || key;
    return `${oid}=${attr.value}`;
  }).join(', ');
}

// Detect key type from PEM key using Node.js crypto
function detectKeyType(pemKey) {
  const keyObject = nodeCrypto.createPrivateKey(pemKey);
  return keyObject.asymmetricKeyType; // 'rsa' or 'ec'
}

// Map Node.js curve names to Web Crypto curve names
function normalizeECCurve(curveName) {
  const curveMap = {
    'prime256v1': 'P-256',
    'secp384r1': 'P-384',
    'secp521r1': 'P-521',
    'P-256': 'P-256',
    'P-384': 'P-384',
    'P-521': 'P-521'
  };
  return curveMap[curveName] || curveName;
}

// Get EC curve from key object
function getECCurve(keyObject) {
  const details = keyObject.asymmetricKeyDetails;
  if (details && details.namedCurve) {
    return normalizeECCurve(details.namedCurve);
  }
  return 'P-256'; // default
}

// Convert PEM key to CryptoKey
async function importPrivateKey(pemKey, algorithm, keyType) {
  // Auto-detect key type if not provided
  const keyObject = nodeCrypto.createPrivateKey(pemKey);
  const detectedKeyType = keyObject.asymmetricKeyType;
  const actualKeyType = keyType || detectedKeyType;

  // Convert to PKCS#8 format
  const pkcs8Pem = keyObject.export({ type: 'pkcs8', format: 'pem' });
  const pemContents = pkcs8Pem
    .replace(/-----BEGIN PRIVATE KEY-----/, '')
    .replace(/-----END PRIVATE KEY-----/, '')
    .replace(/\s/g, '');
  const binaryDer = Buffer.from(pemContents, 'base64');

  let importAlgorithm;
  if (actualKeyType === 'ec') {
    const curve = getECCurve(keyObject);
    importAlgorithm = {
      name: 'ECDSA',
      namedCurve: curve
    };
  } else {
    importAlgorithm = {
      name: 'RSASSA-PKCS1-v1_5',
      hash: getAlgorithmName(algorithm)
    };
  }

  return await crypto.subtle.importKey(
    'pkcs8',
    binaryDer,
    importAlgorithm,
    true,
    ['sign']
  );
}

async function importPublicKey(pemKey, algorithm, keyType, curve) {
  const pemContents = pemKey
    .replace(/-----BEGIN PUBLIC KEY-----/, '')
    .replace(/-----END PUBLIC KEY-----/, '')
    .replace(/\s/g, '');

  const binaryDer = Buffer.from(pemContents, 'base64');

  let importAlgorithm;
  if (keyType === 'ec') {
    importAlgorithm = {
      name: 'ECDSA',
      namedCurve: curve || 'P-256'
    };
  } else {
    importAlgorithm = {
      name: 'RSASSA-PKCS1-v1_5',
      hash: getAlgorithmName(algorithm)
    };
  }

  return await crypto.subtle.importKey(
    'spki',
    binaryDer,
    importAlgorithm,
    true,
    ['verify']
  );
}

async function generatePemAsync(keyPair, attrs, options, ca) {
  const { privateKey, publicKey } = keyPair;

  // Generate serial number
  const serialBytes = crypto.getRandomValues(new Uint8Array(9));
  const serialHex = toPositiveHex(Buffer.from(serialBytes).toString('hex'));

  // Set up dates
  const notBefore = options.notBeforeDate || new Date();
  let notAfter;
  if (options.notAfterDate) {
    notAfter = options.notAfterDate;
  } else {
    notAfter = new Date(notBefore);
    notAfter.setDate(notAfter.getDate() + 365);
  }

  // Default attributes
  attrs = attrs || [
    {
      name: "commonName",
      value: "example.org",
    },
    {
      name: "countryName",
      value: "US",
    },
    {
      shortName: "ST",
      value: "Virginia",
    },
    {
      name: "localityName",
      value: "Blacksburg",
    },
    {
      name: "organizationName",
      value: "Test",
    },
    {
      shortName: "OU",
      value: "Test",
    },
  ];

  const subjectName = convertAttributes(attrs);
  const keyType = options.keyType || 'rsa';
  const signingAlg = getSigningAlgorithm(options.algorithm, keyType);

  // Extract common name for SAN extension
  const commonNameAttr = attrs.find(attr => attr.name === 'commonName' || attr.shortName === 'CN');
  const commonName = commonNameAttr ? commonNameAttr.value : 'localhost';

  // Build extensions array
  const extensions = buildExtensions(options.extensions, commonName);

  let cert;

  if (ca) {
    // Generate certificate signed by CA
    const caCert = new X509Certificate(ca.cert);
    const caPrivateKey = await importPrivateKey(ca.key, options.algorithm || "sha256", keyType);

    cert = await X509CertificateGenerator.create({
      serialNumber: serialHex,
      subject: subjectName,
      issuer: caCert.subject,
      notBefore: notBefore,
      notAfter: notAfter,
      signingAlgorithm: signingAlg,
      publicKey: publicKey,
      signingKey: caPrivateKey,
      extensions: extensions
    });
  } else {
    // Generate self-signed certificate
    cert = await X509CertificateGenerator.createSelfSigned({
      serialNumber: serialHex,
      name: subjectName,
      notBefore: notBefore,
      notAfter: notAfter,
      signingAlgorithm: signingAlg,
      keys: {
        privateKey: privateKey,
        publicKey: publicKey
      },
      extensions: extensions
    });
  }

  // Calculate fingerprint (SHA-1 hash of the certificate)
  const certRaw = cert.rawData;
  const fingerprintBuffer = await crypto.subtle.digest('SHA-1', certRaw);
  const fingerprint = Buffer.from(fingerprintBuffer)
    .toString('hex')
    .match(/.{2}/g)
    .join(':');

  // Export keys to PEM
  const privateKeyDer = await crypto.subtle.exportKey('pkcs8', privateKey);
  const publicKeyDer = await crypto.subtle.exportKey('spki', publicKey);

  let privatePem;
  if (options.passphrase) {
    // Encrypt the private key with the passphrase using Node.js crypto
    const keyObject = nodeCrypto.createPrivateKey({
      key: Buffer.from(privateKeyDer),
      format: 'der',
      type: 'pkcs8'
    });
    privatePem = keyObject.export({
      type: 'pkcs8',
      format: 'pem',
      cipher: 'aes-256-cbc',
      passphrase: options.passphrase
    });
  } else {
    privatePem =
      '-----BEGIN PRIVATE KEY-----\n' +
      Buffer.from(privateKeyDer).toString('base64').match(/.{1,64}/g).join('\n') +
      '\n-----END PRIVATE KEY-----\n';
  }

  const publicPem =
    '-----BEGIN PUBLIC KEY-----\n' +
    Buffer.from(publicKeyDer).toString('base64').match(/.{1,64}/g).join('\n') +
    '\n-----END PUBLIC KEY-----\n';

  const certPem = cert.toString('pem');

  const pem = {
    private: privatePem,
    public: publicPem,
    cert: certPem,
    fingerprint: fingerprint,
  };

  // Client certificate support
  if (options && options.clientCertificate) {
    // Parse clientCertificate options - can be boolean or object
    const clientOpts = typeof options.clientCertificate === 'object' ? options.clientCertificate : {};

    // Resolve client certificate options with fallbacks to deprecated options
    const clientKeySize = clientOpts.keySize || options.clientCertificateKeySize || 2048;
    const clientAlgorithm = clientOpts.algorithm || options.algorithm || "sha1";
    const clientCN = clientOpts.cn || options.clientCertificateCN || "John Doe jdoe123";
    // Client cert uses same key type and curve as main cert by default
    const clientKeyType = clientOpts.keyType || keyType;
    const clientCurve = clientOpts.curve || options.curve || 'P-256';

    const clientKeyAlg = getKeyAlgorithm({
      keyType: clientKeyType,
      keySize: clientKeySize,
      algorithm: clientAlgorithm,
      curve: clientCurve
    });

    const clientKeyPair = await crypto.subtle.generateKey(
      clientKeyAlg,
      true,
      ["sign", "verify"]
    );

    const clientSerialBytes = crypto.getRandomValues(new Uint8Array(9));
    const clientSerialHex = toPositiveHex(Buffer.from(clientSerialBytes).toString('hex'));

    // Resolve client certificate validity dates
    const clientNotBefore = clientOpts.notBeforeDate || new Date();
    let clientNotAfter;
    if (clientOpts.notAfterDate) {
      clientNotAfter = clientOpts.notAfterDate;
    } else {
      clientNotAfter = new Date(clientNotBefore);
      clientNotAfter.setFullYear(clientNotBefore.getFullYear() + 1);
    }

    const clientAttrs = JSON.parse(JSON.stringify(attrs));
    for (let i = 0; i < clientAttrs.length; i++) {
      if (clientAttrs[i].name === "commonName") {
        clientAttrs[i] = {
          name: "commonName",
          value: clientCN
        };
      }
    }

    const clientSubjectName = convertAttributes(clientAttrs);
    const issuerName = convertAttributes(attrs);

    // Signing algorithm for client cert - uses main key type since signed by root
    const clientSigningAlg = getSigningAlgorithm(clientAlgorithm, keyType);

    // Create client cert signed by root key
    const clientCertRaw = await X509CertificateGenerator.create({
      serialNumber: clientSerialHex,
      subject: clientSubjectName,
      issuer: issuerName,
      notBefore: clientNotBefore,
      notAfter: clientNotAfter,
      signingAlgorithm: clientSigningAlg,
      publicKey: clientKeyPair.publicKey,
      signingKey: privateKey // Sign with root private key
    });

    // Export client keys
    const clientPrivateKeyDer = await crypto.subtle.exportKey('pkcs8', clientKeyPair.privateKey);
    const clientPublicKeyDer = await crypto.subtle.exportKey('spki', clientKeyPair.publicKey);

    pem.clientprivate =
      '-----BEGIN PRIVATE KEY-----\n' +
      Buffer.from(clientPrivateKeyDer).toString('base64').match(/.{1,64}/g).join('\n') +
      '\n-----END PRIVATE KEY-----\n';

    pem.clientpublic =
      '-----BEGIN PUBLIC KEY-----\n' +
      Buffer.from(clientPublicKeyDer).toString('base64').match(/.{1,64}/g).join('\n') +
      '\n-----END PUBLIC KEY-----\n';

    pem.clientcert = clientCertRaw.toString('pem');
  }

  // Verify certificate chain
  const x509Cert = new X509Certificate(cert.rawData);
  const certificates = [x509Cert];

  // If CA-signed, include CA cert in the chain for verification
  if (ca) {
    const caCert = new X509Certificate(ca.cert);
    certificates.push(caCert);
  }

  const chainBuilder = new X509ChainBuilder({
    certificates: certificates
  });

  const chain = await chainBuilder.build(x509Cert);
  if (chain.length === 0) {
    throw new Error("Certificate could not be verified.");
  }

  return pem;
}

/**
 * Generate a certificate (async)
 *
 * @param {CertificateField[]} attrs Attributes used for subject.
 * @param {object} options
 * @param {string} [options.keyType="rsa"] Key type: "rsa" or "ec" (elliptic curve)
 * @param {number} [options.keySize=2048] the size for the private key in bits (RSA only)
 * @param {string} [options.curve="P-256"] The elliptic curve to use: "P-256", "P-384", or "P-521" (EC only)
 * @param {object} [options.extensions] additional extensions for the certificate
 * @param {string} [options.algorithm="sha1"] The signature algorithm sha256, sha384, sha512 or sha1
 * @param {Date} [options.notBeforeDate=new Date()] The date before which the certificate should not be valid
 * @param {Date} [options.notAfterDate] The date after which the certificate should not be valid (default: notBeforeDate + 365 days)
 * @param {boolean|object} [options.clientCertificate=false] Generate client cert signed by the original key. Can be `true` for defaults or an options object.
 * @param {number} [options.clientCertificate.keySize=2048] Key size for the client certificate in bits (RSA only)
 * @param {string} [options.clientCertificate.keyType] Key type for client cert (defaults to main keyType)
 * @param {string} [options.clientCertificate.curve] Elliptic curve for client cert (EC only)
 * @param {string} [options.clientCertificate.algorithm] Signature algorithm for client cert (defaults to options.algorithm or "sha1")
 * @param {string} [options.clientCertificate.cn="John Doe jdoe123"] Client certificate's common name
 * @param {Date} [options.clientCertificate.notBeforeDate=new Date()] The date before which the client certificate should not be valid
 * @param {Date} [options.clientCertificate.notAfterDate] The date after which the client certificate should not be valid (default: notBeforeDate + 1 year)
 * @param {string} [options.clientCertificateCN="John Doe jdoe123"] @deprecated Use options.clientCertificate.cn instead
 * @param {number} [options.clientCertificateKeySize] @deprecated Use options.clientCertificate.keySize instead
 * @param {object} [options.ca] CA certificate and key for signing (if not provided, generates self-signed)
 * @param {string} [options.ca.key] CA private key in PEM format
 * @param {string} [options.ca.cert] CA certificate in PEM format
 * @param {string} [options.passphrase] Passphrase to encrypt the private key (uses AES-256-CBC)
 * @returns {Promise<object>} Promise that resolves with certificate data
 */
exports.generate = async function generate(attrs, options) {
  attrs = attrs || undefined;
  options = options || {};

  const keyType = options.keyType || 'rsa';
  const curve = options.curve || 'P-256';

  let keyPair;

  if (options.keyPair) {
    // Import existing key pair
    keyPair = {
      privateKey: await importPrivateKey(options.keyPair.privateKey, options.algorithm || "sha1", keyType),
      publicKey: await importPublicKey(options.keyPair.publicKey, options.algorithm || "sha1", keyType, curve)
    };
  } else {
    // Generate new key pair using appropriate algorithm
    const keyAlg = getKeyAlgorithm(options);
    keyPair = await crypto.subtle.generateKey(
      keyAlg,
      true,
      ["sign", "verify"]
    );
  }

  return await generatePemAsync(keyPair, attrs, options, options.ca);
};

© KUJUNTI.ID