pub fn lower_acl(row: ParseMap) -> ParseMapExpand description
Split an ACL field out of a row into the two storage columns.
Returns the row with ACL removed and the columns added. A row with no ACL gets no columns,
which is what makes it public.
The test upstream applies is falsiness, not “is it an object” (DatabaseController.js:94-96,
literally if (!ACL) return result). Everything truthy falls through to a for...in that reads
.read and .write off each entry, so a string, a number or an array yields no principals but
still writes both columns as empty arrays, which is a master-only row. Skipping the columns
instead writes a row with no _rperm/_wperm at all, and an absent column is public.
Getting this wrong is not a cosmetic divergence. Nothing type-checks ACL on either side, by
design (SchemaController.js:1312-1315), so {"ACL":"x"} reaches here from any client. The
consequential class is _Role: its required-column check tests presence and truthiness only, so
a non-object ACL would satisfy it and then produce a world-writable role that any caller can
add itself to.
The update path applies the same test, in lower_acl_into_update. It did not until a review:
it tested for null alone, so false, 0 and "" fell through and cleared both columns on a
row that already had permissions. Both paths now branch on truthiness, and the tests on each
side loop over the falsy values rather than checking one, because checking one is what let the
other three through.