#!/usr/bin/env node const fs = require('fs'); const crypto = require('crypto'); const path = process.argv[2] || '/opt/dukang/server/dukang-api/.env.production'; function stripQuotes(s) { const t = s.trim(); if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) { return t.slice(1, -1); } return t; } function parseEnvValue(text, key) { const re = new RegExp(`^${key}=(.*)$`, 'm'); const m = text.match(re); if (!m) return null; return stripQuotes(m[1]); } function tryKey(name, key) { const literalN = (key.match(/\\n/g) || []).length; const realN = (key.match(/\n/g) || []).length; const hasBegin = /BEGIN (RSA )?PRIVATE KEY/.test(key); try { crypto.createPrivateKey(key); console.log(`${name}: OK begin=${hasBegin} literalN=${literalN} realN=${realN} len=${key.length}`); return true; } catch (e) { console.log( `${name}: FAIL ${e.message} begin=${hasBegin} literalN=${literalN} realN=${realN} len=${key.length} head=${JSON.stringify(key.slice(0, 48))}`, ); return false; } } const text = fs.readFileSync(path, 'utf8'); const raw = parseEnvValue(text, 'WX_MCH_PRIVATE_KEY'); if (!raw) { console.log('MISSING WX_MCH_PRIVATE_KEY in', path); process.exit(1); } console.log('file=', path); console.log('MOCK_PAY=', parseEnvValue(text, 'MOCK_PAY')); console.log('WX_MINI_APP_ID=', parseEnvValue(text, 'WX_MINI_APP_ID')); console.log('WX_APP_ID=', parseEnvValue(text, 'WX_APP_ID')); console.log('WX_MCH_ID=', parseEnvValue(text, 'WX_MCH_ID')); console.log('WX_PAY_NOTIFY_URL=', parseEnvValue(text, 'WX_PAY_NOTIFY_URL')); const variants = { as_is: raw, unescape_n: raw.replace(/\\n/g, '\n'), unescape_twice: raw.replace(/\\\\n/g, '\\n').replace(/\\n/g, '\n'), strip_cr_unesc: raw.replace(/\\n/g, '\n').replace(/\r/g, ''), // dotenv style sometimes leaves surrounding quotes in process.env quoted_unesc: stripQuotes(raw).replace(/\\n/g, '\n'), }; let ok = false; for (const [name, key] of Object.entries(variants)) { if (tryKey(name, key)) ok = true; } // also simulate dotenv load try { const dotenv = require('dotenv'); const parsed = dotenv.parse(text); const fromDotenv = parsed.WX_MCH_PRIVATE_KEY || ''; console.log('dotenv_raw_literalN=', (fromDotenv.match(/\\n/g) || []).length, 'realN=', (fromDotenv.match(/\n/g) || []).length); tryKey('dotenv_as_is', fromDotenv); tryKey('dotenv_unescape', fromDotenv.replace(/\\n/g, '\n')); } catch (e) { console.log('dotenv skip', e.message); } process.exit(ok ? 0 : 2);