{"version":3,"sources":["jsdelivr-header.js","/npm/ssl-crt@0.0.1-3/index.js"],"names":[],"mappings":"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","file":"/npm/ssl-crt@0.0.1-3/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/ssl-crt@0.0.1-3/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","const { exec, execSync } = require('child_process')\nconst fse = require('fs-extra')\nconst fs = require('fs')\nconst inquirer = require('inquirer')\n\n// 判断系统，暂时这样写，不确定准确性\nconst isOSX = process.platform === 'darwin'\nconst sslCertificateDir = `${process.env.HOME}/.self-signed-cert`\nconst sslConfigFile = `${sslCertificateDir}/ssl.cnf`\nconst sslKeyPath = `${sslCertificateDir}/ssl.key`\nconst sslCrtPath = `${sslCertificateDir}/ssl.crt`\n// 安装到系统上证书的名称\nconst CN = 'genereted by create-self-signed'\n// const CN = 'genereted by ssl-cert-tool@yingchun.fyc'\n// const CN = 'self-signed-cert genereted by ssl-cert-tool@yingchun.fyc'\n// 自签名证书默认支持的域名\nconst DEFAULTDOMAINS = [\n  'localhost',\n  '*.taobao.com',\n  '*.alibaba-inc.com',\n  '*.alimama.com',\n  '*.tanx.com',\n  '*.m.taobao.com'\n]\nconst questions = [\n  /*\n{\n    type: 'input',\n    name: 'C',\n    message: 'Country Name (2 letter code) [CN]',\n    default: 'CN'\n}, {\n    type: 'input',\n    name: 'ST',\n    message: 'State or Province Name (full name) [ZheJiang]',\n    default: 'ZheJiang'\n}, {\n    type: 'input',\n    name: 'L',\n    message: 'Locality Name (eg, city) []',\n    default: 'HangZhou'\n}, {\n    type: 'input',\n    name: 'O',\n    message: 'Organization Name (eg, company) [Internet Widgits Pty Ltd]',\n    default: 'Alibaba'\n}, {\n    type: 'input',\n    name: 'OU',\n    message: 'Organizational Unit Name (eg, section) []',\n    default: 'AlimamaMUX'\n},\n*/{\n    type: 'input',\n    name: 'domains',\n    // message: 'Input the domain name to be self-signed. Separate multiple domain names with commas',\n    message: '输入启动本地HTTPS服务时使用的域名，多个以,分隔，直接回车将使用默认',\n    default: DEFAULTDOMAINS.join(',')\n  }]\n\nconst getInquirerAnswer = async () => {\n  const answer = await inquirer.prompt(questions)\n  let { domains } = answer\n  if (domains) {\n    domains = domains.split(',').map(item => item.trim())\n  } else {\n    domains = []\n  }\n  let allDomains = DEFAULTDOMAINS.concat(domains)\n  // 过滤重复的\n  allDomains = allDomains.reduce((accumulator, currentValue) => {\n    !accumulator.includes(currentValue) && accumulator.push(currentValue)\n    return accumulator\n  }, [])\n  return {\n    ...answer,\n    hosts: allDomains\n  }\n}\n\nconst createCnfFile = ({ hosts }) => {\n  fs.writeFileSync(sslConfigFile, `\n[req] \nprompt = no \ndefault_bits = 4096\ndefault_md = sha256\ndistinguished_name = dn \nx509_extensions = v3_req\n\n[dn] \nC=CN\nST=ZheJiang\nL=HangZhou\nO=Alibaba\nOU=AlimamaMux\nCN=${CN}\nemailAddress=yingchun.fyc@alibaba-inc.com\n\n[v3_req]\nkeyUsage=keyEncipherment, dataEncipherment\nextendedKeyUsage=serverAuth\nsubjectAltName=@alt_names\n\n[alt_names]\n${hosts.map((item, index) => {\n    return `DNS.${index + 1} = ${item}`\n}).join('\\n')}\nIP.1 = 127.0.0.1\n    `.trim())\n}\n\n/**\n * 通过命令行的交互方式收集配置信息，然后生成配置文件\n */\nconst createConfigFile = async (options) => {\n  await fse.ensureDir(sslCertificateDir)\n  createCnfFile(options)\n}\n\n/**\n * 创建密钥和自签名证书\n */\nconst createSSLKeyAndCrt = () => new Promise((resolve, reject) => {\n  // 通过 .cnf 生成 .key、.crt\n  exec(`openssl req \\\n    -new \\\n    -newkey rsa:2048 \\\n    -sha1 \\\n    -days 3650 \\\n    -nodes \\\n    -x509 \\\n    -keyout ${sslKeyPath} \\\n    -out ${sslCrtPath} \\\n    -config ${sslConfigFile}`, (error, stdout, stderr) => {\n    if (error) {\n      // console.log('*error*')\n      // console.log(stderr)\n      resolve({\n        success: false\n      })\n      return\n    }\n    resolve({\n      success: true,\n      sslKeyPath,\n      sslCrtPath\n    })\n  })\n})\n\n/**\n * OSX 在系统钥匙串里添加并始终信任自签名证书\n */\nconst trustSelfSignedCert = () => new Promise((resolve, reject) => {\n  exec(`sudo security add-trusted-cert \\\n    -d -r trustRoot \\\n    -k /Library/Keychains/System.keychain \\\n    ${sslCrtPath}`, (error, stdout, stderr) => {\n    if (error) {\n      resolve(false)\n      return\n    }\n    resolve(true)\n  })\n})\n\n/**\n * 获取该工具添加到钥匙串里自签名证书列表，返回的是证书的sha-1列表\n */\nconst getKeyChainCertSha1List = () => {\n  let sha1List\n  if (isOSX) {\n    try {\n      const sha1Str = isOSX && execSync(`security find-certificate -a -c '${CN}' -Z | grep ^SHA-1`, { encoding: 'utf-8' })\n      sha1List = sha1Str.replace(/SHA-1\\shash:\\s/g, '').split('\\n').filter(sha1 => sha1)\n    } catch (error) {\n      // 找不到\n      sha1List = []\n    }\n  } else {\n    sha1List = []\n  }\n  return sha1List\n}\n\n/**\n * 卸载证书与删除信任\n */\nconst unInstall = async () => {\n  const sha1List = getKeyChainCertSha1List()\n  const existCrtDir = fs.existsSync(sslCertificateDir)\n  if (!sha1List.length && !existCrtDir) {\n    console.log('没有找到该工具安装的证书')\n    // console.log('没有找到该工具创建的自签名证书，钥匙串里也没找到该工具添加的证书')\n    return true\n  }\n\n  // const sha1 = execSync(`child.execSync('openssl x509 -sha1 -in ${sslCrtPath} -noout -fingerprint',{encoding: 'utf-8'}).split('=')[1].replace(/:/g, '').trim()`, {encoding: 'utf-8'})\n  if (sha1List.length) {\n    console.log(`正在删除钥匙串里名称「${CN}」的证书`)\n    try {\n      sha1List.forEach(sha1 => {\n        execSync(`sudo security delete-certificate -Z ${sha1}`)\n      })\n    } catch (error) {\n      console.log('删除失败，流程结束')\n      return false\n    }\n    console.log('删除成功')\n  }\n  if (existCrtDir) {\n    execSync(`rm -rf ${sslCertificateDir}`)\n    console.log(`已经删除存放密钥和证书的目录${sslCertificateDir}`)\n  }\n  console.log('删除完成')\n  return true\n}\n\n/**\n * 创建自签名证书并信任\n */\nconst install = async () => {\n  const sha1List = getKeyChainCertSha1List()\n  const existCrtDir = fs.existsSync(sslCertificateDir)\n  if (sha1List.length || existCrtDir) {\n    let message\n    if (sha1List.length && existCrtDir) {\n      message = `继续操作会删除钥匙串里名称是${CN}的证书和存放密钥和自签名证书的目录${sslCertificateDir}`\n    } else if (sha1List.length) {\n      message = `继续操作会删除钥匙串里名称是${CN}的证书`\n    } else if (existCrtDir) {\n      message = `继续操作会删除存放密钥和自签名证书文件的目录${sslCertificateDir}`\n    }\n    message = '继续操作会覆盖该工具已创建的证书'\n    const answer = await inquirer.prompt([{\n      type: 'confirm',\n      name: 'continue',\n      message,\n      default: false\n    }])\n    // 取消卸载或卸载失败\n    if (!(answer.continue && await unInstall())) return\n    if (!answer.continue) return\n  }\n  const options = await getInquirerAnswer()\n  await createConfigFile(options)\n  const result = await createSSLKeyAndCrt()\n  if (result.success) {\n    // console.log('generate ssl certificate successfully ^.^')\n    console.log('成功创建密钥和自签名证书')\n    // console.log('private key: ', sslKeyPath)\n    // console.log('certificate: ', sslCrtPath)\n  }\n\n  // console.log('try add trust to system.keychain, need you permission')\n  if (isOSX) {\n    console.log('向系统的钥匙串里添加证书并始终信任...')\n    const isTrustCert = await trustSelfSignedCert()\n    if (isTrustCert) {\n      console.log('添加并信任成功，钥匙串里名称为：', CN)\n    } else {\n      console.log('钥匙串添加证书失败')\n    }\n  }\n  console.log('安装结束')\n  console.log('')\n  console.log('可随时通过下面命令行查看自签名信息')\n  console.log('$ self-signed')\n  console.log('')\n  console.log('安装证书的结果：')\n  currentState()\n}\n\n/**\n * 获取自签名证书里支持的域名\n */\nconst getCrtHosts = () => {\n  let hosts\n  try {\n    hosts = execSync(`openssl x509 -in ${sslCrtPath} -noout -text | grep DNS`, { encoding: 'utf-8' }).trim().split(',').filter(item => item.includes('DNS:')).map(item => item.trim().replace(/DNS:/, ''))\n  } catch (error) {\n    // return false\n    return []\n  }\n  return hosts\n}\n\n/**\n * 获取自己创建的证书密钥和自签名证书\n * @param {Array} param0\n */\nconst obtainSelfSigned = async (hosts = DEFAULTDOMAINS) => {\n  const existSslKeyAndCrt = fs.existsSync(sslKeyPath) && fs.existsSync(sslCrtPath)\n  let matched\n  if (existSslKeyAndCrt) {\n    const crtHosts = getCrtHosts()\n    matched = hosts.every(host => {\n      // m.tanx.com 能匹配上 *.tanx.com\n      // (new RegExp('*.tanx.com'.replace('*','^[^.]+'))).test('m.tanx.com') // true\n      return crtHosts.find(crtHostItem => {\n        if (crtHostItem.includes('*')) {\n          return (new RegExp(crtHostItem.replace('*', '^[^.]+'))).test(host)\n        } else {\n          return crtHostItem === host\n        }\n      })\n    })\n    if (!matched) {\n      const addedHosts = hosts.filter(host => {\n        return !crtHosts.find(crtHostItem => {\n          if (crtHostItem.includes('*')) {\n            return (new RegExp(crtHostItem.replace('*', '^[^.]+'))).test(host)\n          } else {\n            return crtHostItem === host\n          }\n        })\n      })\n      hosts = crtHosts.concat(addedHosts)\n    }\n  }\n  if (existSslKeyAndCrt && matched) {\n    const sha1List = getKeyChainCertSha1List()\n    const sha1 = execSync(`openssl x509 -sha1 -in ${sslCrtPath} -noout -fingerprint`, { encoding: 'utf-8' }).split('=')[1].replace(/:/g, '').trim()\n    let certTrusted\n    if (sha1List.includes(sha1)) {\n      certTrusted = true\n    } else if (isOSX) {\n      certTrusted = await trustSelfSignedCert()\n    }\n    return {\n      success: true,\n      sslKeyPath,\n      sslCrtPath,\n      certTrusted\n    }\n  } else if (existSslKeyAndCrt) {\n    // console.log('已有的自签名证书里没有你需要的域名')\n    // const answer = await inquirer.prompt([{\n    //     type: 'confirm',\n    //     name: 'continue',\n    //     message: '是否更新自签名证书，新增要支持的域名',\n    //     default: false\n    // }])\n    if (isOSX) {\n      const sha1List = getKeyChainCertSha1List()\n      // todo 要加sha-1比对才准确\n      if (sha1List.length) {\n        // console.log('自签名证书要新增支持的域名，正在更新自签名证书，需要重新信任')\n        console.log('新增域名需要更新证书并重新信任')\n      } else {\n        console.log('新增域名需要更新证书')\n        // console.log('自签名证书要新增支持的域名，正在更新自签名证书')\n      }\n      try {\n        sha1List.forEach(sha1 => {\n          execSync(`sudo security delete-certificate -Z ${sha1}`)\n        })\n      } catch (error) {\n        return {\n          success: false,\n          message: '卸载老的证书失败，请授权重试'\n          // sslKeyPath,\n          // sslCrtPath,\n        }\n      }\n    } else {\n      console.log('自签名证书要新增支持的域名，正在更新自签名证书')\n    }\n    execSync(`rm -rf ${sslCertificateDir}`)\n  }\n\n  await createConfigFile({ hosts })\n\n  const result = await createSSLKeyAndCrt()\n  if (result.success) {\n    let certTrusted = false\n    if (isOSX) {\n      certTrusted = await trustSelfSignedCert()\n    }\n    return {\n      success: true,\n      sslKeyPath,\n      sslCrtPath,\n      certTrusted\n    }\n  }\n}\n\n/**\n * 自签名信息\n */\nconst currentState = () => {\n  const existSslKeyAndCrt = fs.existsSync(sslKeyPath) && fs.existsSync(sslCrtPath)\n  if (!existSslKeyAndCrt) {\n    console.log('还没有安装自签名证书，运行下面命令安装使用')\n    console.log('$ self-signed install')\n    return\n  }\n  console.log('密钥文件路径：', sslKeyPath)\n  console.log('自签名证书文件路径：', sslCrtPath)\n  console.log('自签名证书已经支持的域名：')\n  const crtHosts = getCrtHosts()\n  console.log(crtHosts.join(','))\n  console.log('自签名证书的有效时间：')\n  console.log(`${execSync(`openssl x509 -in ${sslCrtPath} -noout -dates`, { encoding: 'utf-8' })}`.trim())\n  if (isOSX) {\n    const sha1List = getKeyChainCertSha1List()\n    const sha1 = execSync(`openssl x509 -sha1 -in ${sslCrtPath} -noout -fingerprint`, { encoding: 'utf-8' }).split('=')[1].replace(/:/g, '').trim()\n    if (sha1List.includes(sha1)) {\n      console.log('自签名证书已经添加到钥匙串并被始终信任')\n      console.log(`自签名证书在钥匙串里的名称：${CN}`)\n      console.log(`自签名证书在钥匙串里的sha-1：${sha1}`)\n    } else {\n      console.log('自签名证书还没被添加到钥匙串，可以运行下面命令，执行添加和始终信任')\n      console.log('$ self-signed trust')\n    }\n  }\n  console.log('')\n  console.log('更多使用帮助')\n  console.log('$ self-signed --help')\n  console.log('')\n  console.log('如何配置服务器的HTTPS')\n  console.log('https://yuque.antfin-inc.com/yingchun.fyc/kwg02h/ludtut#60d30e4c')\n\n  console.log('')\n  console.log('如有疑问联系author@慧知')\n}\n\n/**\n * 信任自签名证书\n */\nconst trustSelfSigned = async () => {\n  const existSslKeyAndCrt = fs.existsSync(sslKeyPath) && fs.existsSync(sslCrtPath)\n  if (!existSslKeyAndCrt) {\n    console.log('还没有安装自签名证书，运行下面命令安装使用')\n    console.log('$ self-signed install')\n    return\n  }\n  const sha1List = getKeyChainCertSha1List()\n  const sha1 = execSync(`openssl x509 -sha1 -in ${sslCrtPath} -noout -fingerprint`, { encoding: 'utf-8' }).split('=')[1].replace(/:/g, '').trim()\n  if (sha1List.includes(sha1)) {\n    console.log('钥匙串里已经添加过，无须重复添加')\n    console.log('在钥匙串里证书的信息：')\n    console.log(`名称: ${CN}`)\n    console.log(`sha-1: ${sha1}`)\n  } else {\n    const added = await trustSelfSignedCert()\n    if (added) {\n    //   console.log(`已成功添加自签名，名称是${CN}，sha-1是${sha1}`)\n      console.log(`添加并信任成功，钥匙串里名称是\"${CN}\"`)\n    } else {\n      console.log('添加失败')\n    }\n  }\n}\n\n/**\n * 添加新的要支持的域名\n * @param {*} hosts\n */\nconst addHosts = async (hosts = []) => {\n  if (!hosts.length) {\n    console.log('输入要支持的host')\n    return\n  }\n  const existSslKeyAndCrt = fs.existsSync(sslKeyPath) && fs.existsSync(sslCrtPath)\n  if (!existSslKeyAndCrt) {\n    console.log('还没有安装自签名证书，运行下面命令安装使用')\n    console.log('$ self-signed install')\n    return\n  }\n\n  const crtHosts = getCrtHosts()\n  const matched = hosts.every(host => {\n    return crtHosts.find(crtHostItem => {\n      if (crtHostItem.includes('*')) {\n        return (new RegExp(crtHostItem.replace('*', '^[^.]+'))).test(host)\n      } else {\n        return crtHostItem === host\n      }\n    })\n  })\n  if (matched) {\n    console.log('证书已经支持该域名，无须添加了')\n    return\n  }\n  if (!matched) {\n    console.log(crtHosts)\n    const addedHosts = hosts.filter(host => {\n      return !crtHosts.find(crtHostItem => {\n        if (crtHostItem.includes('*')) {\n          return (new RegExp(crtHostItem.replace('*', '^[^.]+'))).test(host)\n        } else {\n          return crtHostItem === host\n        }\n      })\n    })\n    console.log(addedHosts)\n    hosts = crtHosts.concat(addedHosts)\n  }\n\n  let sha1List\n  if (isOSX) {\n    sha1List = getKeyChainCertSha1List()\n    // todo 要加sha-1比对才准确\n    if (sha1List.length) {\n      console.log('新增域名需要更新证书并重新信任')\n    } else {\n      console.log('正在更新证书')\n    }\n    try {\n      sha1List.forEach(sha1 => {\n        execSync(`sudo security delete-certificate -Z ${sha1}`)\n      })\n    } catch (error) {\n      console.log('新增域名失败')\n      return\n    }\n  } else {\n    console.log('正在更新证书')\n  }\n  execSync(`rm -rf ${sslCertificateDir}`)\n\n  await createConfigFile({ hosts })\n\n  const result = await createSSLKeyAndCrt()\n  if (result.success) {\n    let certTrusted = false\n    if (isOSX && sha1List.length) {\n      certTrusted = trustSelfSignedCert()\n    }\n    console.log('更新成功')\n    console.log('更新后支持的域名')\n    const crtHosts = getCrtHosts()\n    console.log(crtHosts.join(','))\n    console.log('更新后证书的起止有效时间：')\n    console.log(`${execSync(`openssl x509 -in ${sslCrtPath} -noout -dates`, { encoding: 'utf-8' })}`.trim())\n  }\n}\n\nconst removeSelfSigned = () => {\n\n}\n\nmodule.exports = {\n  obtainSelfSigned,\n  removeSelfSigned,\n  currentState,\n  install,\n  unInstall,\n  trustSelfSigned,\n  addHosts\n}\n"]}