137 lines
3.6 KiB
JavaScript
137 lines
3.6 KiB
JavaScript
/**
|
|
* Host openssl-compatible subset using bare-crypto (no OpenSSL binary).
|
|
* Supported: `version`, `rand -hex N`, `dgst -sha256 [-binary] PATH`.
|
|
*/
|
|
import { createHash, randomBytes } from 'bare-crypto'
|
|
import b4a from 'b4a'
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string[]} argv
|
|
*/
|
|
export async function runOpensslCli(ctx, argv) {
|
|
const args = argv.slice(1).filter((a) => a !== '--')
|
|
if (
|
|
args.length === 0 ||
|
|
args[0] === '-h' ||
|
|
args[0] === '-help' ||
|
|
args[0] === '--help'
|
|
) {
|
|
ctx.console.log(
|
|
'usage: openssl version\n' +
|
|
' openssl rand -hex NUM_BYTES\n' +
|
|
' openssl dgst -sha256 [-binary] FILE\n' +
|
|
'Bare OS: bare-crypto backend (not OpenSSL).\n'
|
|
)
|
|
return
|
|
}
|
|
|
|
if (args[0] === 'version') {
|
|
ctx.console.log('Bare OS openssl compatibility (bare-crypto)')
|
|
return
|
|
}
|
|
|
|
if (args[0] === 'rand') {
|
|
let hex = false
|
|
let n = 32
|
|
for (let i = 1; i < args.length; i++) {
|
|
if (args[i] === '-hex') hex = true
|
|
else if (/^\d+$/.test(args[i])) n = Number.parseInt(args[i], 10)
|
|
}
|
|
if (!hex) {
|
|
ctx.console.error('openssl rand: only `openssl rand -hex NUM_BYTES` is supported')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
if (!Number.isFinite(n) || n < 1 || n > 65536) {
|
|
ctx.console.error('openssl rand: invalid size')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
const raw = randomBytes(n)
|
|
ctx.console.log(Buffer.from(raw).toString('hex'))
|
|
return
|
|
}
|
|
|
|
if (args[0] === 'dgst') {
|
|
let binary = false
|
|
let i = 1
|
|
for (; i < args.length; i++) {
|
|
if (args[i] === '-sha256') continue
|
|
if (args[i] === '-binary') {
|
|
binary = true
|
|
continue
|
|
}
|
|
if (args[i].startsWith('-')) {
|
|
ctx.console.error('openssl dgst: unsupported flag ' + args[i])
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
break
|
|
}
|
|
const filePath = args[i]
|
|
if (!filePath) {
|
|
ctx.console.error('openssl dgst: missing file')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
const vfs = ctx.vfs
|
|
if (!vfs || typeof vfs.readFile !== 'function') {
|
|
ctx.console.error('openssl dgst: vfs.readFile unavailable')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
let abs
|
|
try {
|
|
abs = vfs.resolveLogical(String(filePath))
|
|
} catch {
|
|
ctx.console.error('openssl dgst: bad path')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
let buf
|
|
try {
|
|
buf = await vfs.readFile(abs)
|
|
} catch (e) {
|
|
ctx.console.error(
|
|
'openssl dgst: ' + ((e && /** @type {Error} */ (e).message) || String(e))
|
|
)
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
const h = createHash('sha256')
|
|
h.update(b4a.isBuffer(buf) ? buf : new Uint8Array(buf))
|
|
const digest = h.digest()
|
|
if (binary) {
|
|
const u8 =
|
|
digest instanceof Uint8Array
|
|
? digest
|
|
: typeof Buffer !== 'undefined'
|
|
? new Uint8Array(Buffer.from(digest))
|
|
: new Uint8Array(0)
|
|
if (typeof ctx.bareOsBinWrite === 'function') {
|
|
ctx.bareOsBinWrite(u8)
|
|
} else {
|
|
ctx.console.error(
|
|
'openssl dgst -binary: binary stdout requires ctx.bareOsBinWrite'
|
|
)
|
|
ctx.exitCode = 1
|
|
}
|
|
} else {
|
|
const hex =
|
|
typeof digest === 'string'
|
|
? digest
|
|
: typeof Buffer !== 'undefined'
|
|
? Buffer.from(digest).toString('hex')
|
|
: [...new Uint8Array(digest)]
|
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
.join('')
|
|
ctx.console.log(hex + ' *' + filePath)
|
|
}
|
|
return
|
|
}
|
|
|
|
ctx.console.error('openssl: unsupported command ' + args[0])
|
|
ctx.exitCode = 1
|
|
}
|