fix(page-data): isolate owner API from public pages
This commit is contained in:
@@ -41,12 +41,21 @@ export function detectPageDataDatasetUsageFromHtml(html) {
|
||||
for (const match of text.matchAll(/\.listRows\(\s*['"]([^'"]+)['"]/g)) {
|
||||
remember(match[1], { read: true });
|
||||
}
|
||||
for (const match of text.matchAll(/\.deleteRow\(\s*['"]([^'"]+)['"]/g)) {
|
||||
// The browser client's deleteRow endpoint intentionally falls back to a
|
||||
// soft delete unless a policy explicitly grants hard_delete. A page using
|
||||
// this API must therefore only require the safe, default capability.
|
||||
remember(match[1], { softDelete: true });
|
||||
}
|
||||
for (const match of text.matchAll(/\.insertRow\(\s*([A-Za-z_$][\w$]*)/g)) {
|
||||
remember(constants.get(match[1]) ?? match[1], { insert: true });
|
||||
}
|
||||
for (const match of text.matchAll(/\.listRows\(\s*([A-Za-z_$][\w$]*)/g)) {
|
||||
remember(constants.get(match[1]) ?? match[1], { read: true });
|
||||
}
|
||||
for (const match of text.matchAll(/\.deleteRow\(\s*([A-Za-z_$][\w$]*)/g)) {
|
||||
remember(constants.get(match[1]) ?? match[1], { softDelete: true });
|
||||
}
|
||||
|
||||
return datasets;
|
||||
}
|
||||
@@ -55,7 +64,16 @@ export function inferPageDataBindAccessMode(relativePath, html) {
|
||||
const usage = detectPageDataDatasetUsageFromHtml(html);
|
||||
const hasRead = [...usage.values()].some((item) => item.read);
|
||||
const hasInsert = [...usage.values()].some((item) => item.insert);
|
||||
if (/-admin\.html$/i.test(String(relativePath ?? '')) || (hasRead && !hasInsert)) {
|
||||
// A page that exchanges a password for a Page Data token is intentionally
|
||||
// protected even when it both reads and writes its dataset (for example, a
|
||||
// personal tracker). Do not silently re-bind it as public merely because it
|
||||
// is not named "-admin.html".
|
||||
const usesServerAuthentication = /\.\s*authenticate\s*\(/.test(String(html ?? ''));
|
||||
if (
|
||||
/-admin\.html$/i.test(String(relativePath ?? '')) ||
|
||||
(hasRead && !hasInsert) ||
|
||||
usesServerAuthentication
|
||||
) {
|
||||
return 'password';
|
||||
}
|
||||
return 'public';
|
||||
@@ -122,6 +140,10 @@ export function buildPageDataPolicyDatasetsFromRegistry({ html, registryDatasets
|
||||
entry.columns.read = registered.columns?.read ?? [];
|
||||
}
|
||||
}
|
||||
if (perms.softDelete) {
|
||||
entry.softDelete = true;
|
||||
entry.columns.soft_delete = registered.columns?.soft_delete ?? ['id'];
|
||||
}
|
||||
|
||||
datasets[name] = entry;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user