Auto Create Autorized_Keys

This commit is contained in:
Raven Scott
2026-04-08 23:07:07 -04:00
parent 4ad6c08129
commit 8d9f79600c
3 changed files with 114 additions and 7 deletions
+5 -5
View File
@@ -3,7 +3,10 @@
*/
import b4a from 'b4a'
import bareSsh2 from 'bare-ssh2'
import { parseSshdConfig } from './sshd-config-parse.js'
import {
logicalAuthorizedKeysPath,
parseSshdConfig
} from './sshd-config-parse.js'
import { appendVarLog, BARE_OS_VAR_LOG_DIR } from './bare-os-var-log.js'
import { registerBareService } from './bare-initd.js'
import { execShellLine, loadBarerc } from './shell.js'
@@ -242,10 +245,7 @@ async function loadAuthorizedKeyObjects(ctx, authKeysRel) {
const vfs = ctx.vfs
const env = vfs?.env
const home = String(env?.HOME || '/home/guest')
const path =
authKeysRel.startsWith('/') || authKeysRel.startsWith('~/')
? authKeysRel
: `${home.replace(/\/+$/, '')}/${authKeysRel.replace(/^\/+/, '')}`
const path = logicalAuthorizedKeysPath(home, authKeysRel)
const abs = vfs.resolveLogical(path)
let raw
try {
@@ -21,9 +21,76 @@ import {
vaultKeyFromSecret
} from './identity-account.js'
import { bareOsResetShellIdentityState } from './shell.js'
import {
logicalAuthorizedKeysPath,
parseSshdConfig,
SSHD_DEFAULT_AUTHORIZED_KEYS_FILE
} from './sshd-config-parse.js'
const LEGACY_ROOT_MIGRATION_STATE = '/.bare-os/migration/legacy-root-v1.json'
/** @param {string} abs */
function posixDirnameForLogicalAbs(abs) {
const s = String(abs || '').replace(/\/+$/, '')
if (!s || s === '/') return '/'
const i = s.lastIndexOf('/')
if (i <= 0) return '/'
return s.slice(0, i) || '/'
}
/**
* Create `$HOME/.ssh` and starter `authorized_keys` when missing (path from `/etc/ssh/sshd_config` when present).
* @param {Record<string, unknown>} ctx
*/
async function ensureAuthorizedKeysFile(ctx) {
const vfs = ctx.vfs
if (
!vfs ||
typeof vfs.mkdir !== 'function' ||
typeof vfs.readFile !== 'function' ||
typeof vfs.writeFile !== 'function' ||
typeof vfs.resolveLogical !== 'function'
)
return
let rel = SSHD_DEFAULT_AUTHORIZED_KEYS_FILE
try {
const cfgAbs = vfs.resolveLogical('/etc/ssh/sshd_config')
const buf = await vfs.readFile(cfgAbs)
if (buf != null && b4a.from(buf).length)
rel = parseSshdConfig(b4a.toString(buf)).authorizedKeysFile
} catch {
/* no readable sshd_config */
}
const home = String(vfs.env?.HOME || '/home/guest')
const logical = logicalAuthorizedKeysPath(home, rel)
let abs
try {
abs = vfs.resolveLogical(logical)
} catch {
return
}
const parent = posixDirnameForLogicalAbs(abs)
try {
await vfs.mkdir(parent, { recursive: true })
} catch {
/* exists */
}
try {
const existing = await vfs.readFile(abs)
if (existing != null) return
} catch {
/* missing */
}
try {
await vfs.writeFile(
abs,
b4a.from('# Bare OS: add OpenSSH public keys here (one per line).\n')
)
} catch {
/* ignore */
}
}
/**
* Mirror vault NDJSON checkpoints into the tamper-evident host audit chain when the booter exposes it.
* @param {Record<string, unknown>} ctx
@@ -222,6 +289,11 @@ export async function applyGuestEnv(ctx) {
} catch (e) {
ctx.console?.error?.('[bare-os] loadBarerc: ' + (e?.message || e))
}
try {
await ensureAuthorizedKeysFile(ctx)
} catch (e) {
ctx.console?.error?.('[bare-os] ensureAuthorizedKeysFile: ' + (e?.message || e))
}
}
/**
@@ -271,6 +343,11 @@ export async function applyUnlockedEnv(ctx, publicKey, secretKey) {
} catch (e) {
ctx.console?.error?.('[bare-os] loadBarerc: ' + (e?.message || e))
}
try {
await ensureAuthorizedKeysFile(ctx)
} catch (e) {
ctx.console?.error?.('[bare-os] ensureAuthorizedKeysFile: ' + (e?.message || e))
}
}
/**
@@ -328,7 +405,14 @@ export async function ensureGuestHome(ctx) {
}
try {
const existing = await drive.get(keepPath)
if (existing) return
if (existing) {
try {
await ensureAuthorizedKeysFile(ctx)
} catch (e) {
ctx.console?.error?.('[bare-os] ensureAuthorizedKeysFile: ' + (e?.message || e))
}
return
}
} catch {
/* missing */
}
@@ -337,6 +421,11 @@ export async function ensureGuestHome(ctx) {
} catch {
/* ignore */
}
try {
await ensureAuthorizedKeysFile(ctx)
} catch (e) {
ctx.console?.error?.('[bare-os] ensureAuthorizedKeysFile: ' + (e?.message || e))
}
}
/**
@@ -1,6 +1,24 @@
/**
* Minimal sshd_config subset parser (key value pairs and repeats).
* Lives under bare-os-booter so Pear bundles it with the booter (not bare-os-openssh).
*/
/** Default `AuthorizedKeysFile` when sshd_config omits it (OpenSSH-style relative → $HOME). */
export const SSHD_DEFAULT_AUTHORIZED_KEYS_FILE = '.ssh/authorized_keys'
/**
* Build the logical path bare-openssh uses before `vfs.resolveLogical` (must stay in sync).
* @param {string} [home]
* @param {string} [authKeysRel]
*/
export function logicalAuthorizedKeysPath(home, authKeysRel) {
const h = String(home || '/home/guest').replace(/\/+$/, '')
const rel = String(authKeysRel ?? SSHD_DEFAULT_AUTHORIZED_KEYS_FILE).trim()
if (rel.startsWith('/') || rel.startsWith('~/')) return rel
return `${h}/${rel.replace(/^\/+/, '')}`
}
/**
* @param {string} text
* @returns {{
* port: number,
@@ -28,7 +46,7 @@ export function parseSshdConfig(text) {
allowTcpForwarding: false,
maxAuthTries: 6,
clientAliveInterval: 0,
authorizedKeysFile: '.ssh/authorized_keys',
authorizedKeysFile: SSHD_DEFAULT_AUTHORIZED_KEYS_FILE,
subsystemSftp: 'internal-sftp'
}