You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

102 lines
4.4 KiB

-- Lossy revert: the legacy role/`access_all` schema cannot represent the nine Custom permissions or
-- the Custom role. Two explicit operator decisions are required before anything is touched, and both
-- are consumed at the end, so one decision covers one downgrade. Operators who only need the older
-- binary to start again can use the self-contained script per backend in tools/custom_role_rollback/.
-- 1) Acknowledge the loss. Create this table with every Vaultwarden instance stopped:
--
-- CREATE TABLE __vw_allow_custom_role_downgrade (acknowledged INTEGER NOT NULL PRIMARY KEY);
--
-- The duplicate key aborts the revert. It is only inserted while the acknowledgement is absent.
CREATE TEMPORARY TABLE __vw_custom_role_downgrade_guard (
blocked INTEGER NOT NULL PRIMARY KEY
);
INSERT INTO __vw_custom_role_downgrade_guard (blocked) VALUES (1);
INSERT INTO __vw_custom_role_downgrade_guard (blocked)
SELECT 1
WHERE NOT EXISTS (
SELECT 1 FROM sqlite_master
WHERE type = 'table' AND name = '__vw_allow_custom_role_downgrade'
);
DROP TABLE __vw_custom_role_downgrade_guard;
-- 2) Decide which Custom memberships come back as Manager. The legacy role is not a subset of what a
-- Custom member holds, so handing it out automatically would *grant* authority during a
-- downgrade; it takes a current, deliberate list. An empty list is a valid answer and maps every
-- Custom member to plain User. See README.md in tools/custom_role_rollback/.
--
-- CREATE TABLE __vw_rollback_manager_allowlist (users_organizations_uuid TEXT NOT NULL PRIMARY KEY);
-- INSERT INTO __vw_rollback_manager_allowlist (users_organizations_uuid) VALUES ('<MEMBERSHIP_UUID>');
--
-- The duplicate key aborts the revert. It is only inserted while the list is absent.
CREATE TEMPORARY TABLE __vw_rollback_allowlist_guard (
blocked INTEGER NOT NULL PRIMARY KEY
);
INSERT INTO __vw_rollback_allowlist_guard (blocked) VALUES (1);
INSERT INTO __vw_rollback_allowlist_guard (blocked)
SELECT 1
WHERE NOT EXISTS (
SELECT 1 FROM sqlite_master
WHERE type = 'table' AND name = '__vw_rollback_manager_allowlist'
);
DROP TABLE __vw_rollback_allowlist_guard;
-- Roles and `access_all` are recomputed together, because in the old schema they are not independent:
--
-- * Owners and Admins always carried the bit and it grants them nothing extra;
-- * an allowlisted Custom member becomes a Manager, keeping the bit only with all three collection
-- permissions -- `access_all` also carried collection deletion there, so an Edit-only member must
-- not silently gain it;
-- * everything else becomes a plain User without the bit. `User + access_all` is the one legacy
-- state the upgrade refuses, so leaving it set would strand the database.
--
-- Group-derived Manager authority needs no restoring: `groups.access_all` was never modified, so the
-- older binary derives it again for whoever comes back as Manager.
CREATE TABLE users_organizations_old (
uuid TEXT NOT NULL PRIMARY KEY,
user_uuid TEXT NOT NULL REFERENCES users (uuid),
org_uuid TEXT NOT NULL REFERENCES organizations (uuid),
access_all BOOLEAN NOT NULL,
akey TEXT NOT NULL,
status INTEGER NOT NULL,
atype INTEGER NOT NULL,
reset_password_key TEXT,
external_id TEXT,
invited_by_email TEXT DEFAULT NULL,
UNIQUE (user_uuid, org_uuid)
);
INSERT INTO users_organizations_old (
uuid, user_uuid, org_uuid, access_all, akey, status, atype,
reset_password_key, external_id, invited_by_email
)
SELECT
uo.uuid, uo.user_uuid, uo.org_uuid,
CASE
WHEN uo.atype IN (0, 1) THEN TRUE
WHEN uo.atype = 4
AND uo.uuid IN (SELECT users_organizations_uuid FROM __vw_rollback_manager_allowlist)
AND uo.create_new_collections = TRUE
AND uo.edit_any_collection = TRUE
AND uo.delete_any_collection = TRUE THEN TRUE
ELSE FALSE
END,
uo.akey, uo.status,
CASE
WHEN uo.atype = 4
AND uo.uuid IN (SELECT users_organizations_uuid FROM __vw_rollback_manager_allowlist) THEN 3
WHEN uo.atype = 4 THEN 2
ELSE uo.atype
END,
uo.reset_password_key, uo.external_id, uo.invited_by_email
FROM users_organizations AS uo;
DROP TABLE users_organizations;
ALTER TABLE users_organizations_old RENAME TO users_organizations;
-- Both decisions authorized *this* downgrade, not the next one.
DROP TABLE IF EXISTS __vw_allow_custom_role_downgrade;
DROP TABLE IF EXISTS __vw_rollback_manager_allowlist;