All files / packages/mkcert/src verify.ts

100% Statements 84/84
92.3% Branches 12/13
100% Functions 3/3
100% Lines 84/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104  1x 1x 1x 1x 1x   1x 2x 2x 2x 2x 2x 2x 2x   2x 1x 1x 2x   2x 1x 2x 2x   1x 2x 2x 2x 2x 2x   2x 1x   1x 1x 1x   1x 1x   1x   1x 2x   2x 1x 2x 2x   3x 3x 3x 3x   3x 3x   3x 3x 3x 3x 3x 3x 3x 3x   3x 3x   3x 2x 2x 2x 1x 1x 1x 1x   3x 3x 3x   3x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x   3x 3x 3x 3x  
import type { Certificate, Prettify, VerifyOptions } from './type'
import crypto from 'node:crypto'
import tls from 'node:tls'
import dayjs from 'dayjs'
import forge from 'node-forge'
import logger from './logger'
 
export function verifyCertificateByTLS(options: Prettify<VerifyOptions & Certificate>) {
  const secureContext = tls.createSecureContext({ key: options.key, cert: options.cert })
  const tlsOptions: tls.ConnectionOptions = {
    host: options.host,
    port: Number(options.port),
    secureContext,
    rejectUnauthorized: options.rejectUnauthorized,
  }
 
  const socket = tls.connect(tlsOptions, () => {
    logger.info('证书有效')
    socket.end()
  })
 
  socket.on('error', (err) => {
    logger.error(err.toString())
  })
}
 
export function verifyCertificateValidityByTLS(options: Prettify<VerifyOptions>) {
  const tlsOptions: tls.ConnectionOptions = {
    host: options.host,
    port: Number(options.port),
    rejectUnauthorized: options.rejectUnauthorized,
  }
 
  const socket = tls.connect(tlsOptions, () => {
    const cert = socket.getPeerCertificate()
 
    const validFrom = new Date(cert.valid_from).getTime()
    const validTo = new Date(cert.valid_to).getTime()
    const now = Date.now()
 
    if (now > validFrom && now < validTo)
      logger.info('证书有效')
    else
      logger.warn('证书无效:不在有效期内')
 
    socket.end()
  })
 
  socket.on('error', (err) => {
    logger.error(`${err}`)
  })
}
 
export async function verifyCertificate(keyPem: string, certPem: string) {
  const cert = forge.pki.certificateFromPem(certPem)
  const privateKey = forge.pki.privateKeyFromPem(keyPem)
  const publicKey = cert.publicKey as forge.pki.rsa.PublicKey
 
  const certModulus = publicKey.n.toString(16)
  const keyModulus = privateKey.n.toString(16)
 
  const certModulusMd5 = crypto
    .createHash('md5')
    .update(certModulus)
    .digest('hex')
  const keyModulusMd5 = crypto
    .createHash('md5')
    .update(keyModulus)
    .digest('hex')
 
  const matchs: boolean[] = []
  const messages: string[] = []
 
  if (certModulusMd5 === keyModulusMd5) {
    matchs.push(true)
    messages.push('证书和私钥匹配')
  }
  else {
    matchs.push(false)
    messages.push('证书和私钥不匹配')
  }
 
  const now = new Date()
  const validFrom = cert.validity.notBefore
  const validTo = cert.validity.notAfter
 
  if (now > validFrom && now < validTo) {
    matchs.push(true)
    messages.push(
      `证书在有效期内,有效期:${dayjs(validFrom).format('YYYY-MM-DD HH:mm:ss')} ~ ${dayjs(validTo).format('YYYY-MM-DD HH:mm:ss')}`,
    )
  }
  else {
    matchs.push(false)
    messages.push(
      `证书不在有效期内,有效期:${dayjs(validFrom).format('YYYY-MM-DD HH:mm:ss')} - ${dayjs(validTo).format('YYYY-MM-DD HH:mm:ss')}`,
    )
  }
 
  const match = matchs.every(m => m)
  const message = messages.join(', ')
  return { match, message }
}