refactor(okr): trekk path-confinement ut til delt modul
This commit is contained in:
parent
3ebb333381
commit
892acf1d87
2 changed files with 57 additions and 22 deletions
|
|
@ -38,6 +38,10 @@ import path from 'node:path';
|
||||||
import { homedir } from 'node:os';
|
import { homedir } from 'node:os';
|
||||||
|
|
||||||
import { writeFrontmatter, parseFrontmatter } from './frontmatter.mjs';
|
import { writeFrontmatter, parseFrontmatter } from './frontmatter.mjs';
|
||||||
|
import {
|
||||||
|
resolveUnderBundle as resolveUnderBundleShared,
|
||||||
|
assertRealUnderBundle as assertRealUnderBundleShared,
|
||||||
|
} from './path-confinement.mjs';
|
||||||
|
|
||||||
// Den home-kanoniske org-profil-rota. Ingestion skal ALDRI skrive hit (den eies
|
// Den home-kanoniske org-profil-rota. Ingestion skal ALDRI skrive hit (den eies
|
||||||
// av write-org-profile.mjs); prosjekt-bundlen er .claude/okr under cwd.
|
// av write-org-profile.mjs); prosjekt-bundlen er .claude/okr under cwd.
|
||||||
|
|
@ -53,28 +57,14 @@ function writeAtomic(target, data) {
|
||||||
renameSync(tmp, target);
|
renameSync(tmp, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolver en bundle-relativ sti og asserter at den blir UNDER bundle-rota.
|
// M2 (A1): tolags path-confinement (leksikalsk + symlink) bor i
|
||||||
// Avviser '..'-escape og absolutt-override (path.resolve lar en absolutt rel
|
// lib/path-confinement.mjs -- delt med lib/arkivklar.mjs, som trenger NOEYAKTIG
|
||||||
// vinne -- containment-sjekken fanger det).
|
// samme regel paa lesesiden. Wrapperne her binder bare modulnavnet inn i
|
||||||
function resolveUnderBundle(resolvedBundle, rel) {
|
// feilmeldingen, saa den kallende modulen fortsatt er identifiserbar.
|
||||||
const resolved = path.resolve(resolvedBundle, rel);
|
const resolveUnderBundle = (resolvedBundle, rel) =>
|
||||||
if (resolved !== resolvedBundle && !resolved.startsWith(resolvedBundle + path.sep)) {
|
resolveUnderBundleShared(resolvedBundle, rel, 'innboks-write');
|
||||||
throw new Error(`innboks-write: maal-sti utenfor bundle-rot avvist: ${rel}`);
|
const assertRealUnderBundle = (realBundle, p, what) =>
|
||||||
}
|
assertRealUnderBundleShared(realBundle, p, what, 'innboks-write');
|
||||||
return resolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
// M2 (A1): den leksikalske sjekken over slipper symlinks -- en symlinket
|
|
||||||
// katalog/original INNE i bundlen kan peke UT av den. realpathSync paa den
|
|
||||||
// faktiske noden (destinasjons-parent etter mkdir / original foer peker-skriv)
|
|
||||||
// maa ogsaa lande under bundle-rotas realpath, ellers avvises skrivet.
|
|
||||||
function assertRealUnderBundle(realBundle, p, what) {
|
|
||||||
const real = realpathSync(p);
|
|
||||||
if (real !== realBundle && !real.startsWith(realBundle + path.sep)) {
|
|
||||||
throw new Error(`innboks-write: ${what} resolverer utenfor bundle-rot (symlink-escape avvist): ${p}`);
|
|
||||||
}
|
|
||||||
return real;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destinasjons-parent opprettes, realpath-sjekkes, DERETTER skrives det atomisk.
|
// Destinasjons-parent opprettes, realpath-sjekkes, DERETTER skrives det atomisk.
|
||||||
function writeConfined(realBundle, target, data, what) {
|
function writeConfined(realBundle, target, data, what) {
|
||||||
|
|
|
||||||
45
lib/path-confinement.mjs
Normal file
45
lib/path-confinement.mjs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// path-confinement.mjs
|
||||||
|
// Delt lesegrense/skrivegrense mot en bundle-rot. Trukket ut av
|
||||||
|
// lib/innboks-write.mjs (D7 steg 17) fordi arkivklar-traverseringen trenger
|
||||||
|
// NOEYAKTIG samme regel paa lesesiden som ingestion har paa skrivesiden.
|
||||||
|
//
|
||||||
|
// EN delt regel, ett sted -- samme disiplin som unquote() i lib/frontmatter.mjs.
|
||||||
|
// To kopier av en sikkerhetsregel maa endres i takt for alltid, og gjoer det ikke.
|
||||||
|
//
|
||||||
|
// Tolags, fordi de to lagene fanger ULIKE angrepsformer:
|
||||||
|
// (1) LEKSIKALSK (resolveUnderBundle) -- '..'-escape og absolutt-override.
|
||||||
|
// path.resolve() lar en absolutt `rel` vinne over rota; containment-sjekken
|
||||||
|
// fanger det. path.sep i prefikssjekken er load-bearing: uten den tillater
|
||||||
|
// basen /uploads ogsaa soesken-katalogen /uploads-other.
|
||||||
|
// (2) SYMLINK (assertRealUnderBundle) -- path.resolve() loeser IKKE symlenker,
|
||||||
|
// saa en symlinket node INNE i bundlen kan peke UT av den. realpathSync paa
|
||||||
|
// den faktiske noden maa ogsaa lande under rotas realpath.
|
||||||
|
// Lag (1) alene er utilstrekkelig, og lag (2) alene kaster paa stier som ikke
|
||||||
|
// finnes ennaa. Begge trengs.
|
||||||
|
|
||||||
|
import path from 'node:path';
|
||||||
|
import { realpathSync } from 'node:fs';
|
||||||
|
|
||||||
|
// Resolver en bundle-relativ sti og asserter at den blir UNDER bundle-rota.
|
||||||
|
// `hvem` gaar inn i feilmeldingen slik at kalleren er identifiserbar -- den
|
||||||
|
// eneste grunnen funksjonen tar den i det hele tatt.
|
||||||
|
export function resolveUnderBundle(resolvedBundle, rel, hvem = 'path-confinement') {
|
||||||
|
const resolved = path.resolve(resolvedBundle, rel);
|
||||||
|
if (resolved !== resolvedBundle && !resolved.startsWith(resolvedBundle + path.sep)) {
|
||||||
|
throw new Error(`${hvem}: maal-sti utenfor bundle-rot avvist: ${rel}`);
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
// realpathSync kaster ENOENT paa en sti som ikke finnes. Det er kallerens ansvar
|
||||||
|
// aa kalle denne paa en node som ER opprettet (destinasjons-parent etter mkdir,
|
||||||
|
// eller en fil som faktisk ligger der) -- vi pakker den derfor IKKE inn i en
|
||||||
|
// try/catch her: en ENOENT skal boble som ENOENT, ikke maskeres som et
|
||||||
|
// confinement-brudd. De to feilene krever ulik handling hos kalleren.
|
||||||
|
export function assertRealUnderBundle(realBundle, p, what, hvem = 'path-confinement') {
|
||||||
|
const real = realpathSync(p);
|
||||||
|
if (real !== realBundle && !real.startsWith(realBundle + path.sep)) {
|
||||||
|
throw new Error(`${hvem}: ${what} resolverer utenfor bundle-rot (symlink-escape avvist): ${p}`);
|
||||||
|
}
|
||||||
|
return real;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue