Forgot Passaord

This commit is contained in:
root
2025-11-05 19:46:57 +00:00
parent 3140a024e6
commit 71ab82b592
31 changed files with 5193 additions and 1259 deletions
+624
View File
@@ -44,6 +44,10 @@ CREATE TABLE IF NOT EXISTS users (
avatar_color TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
last_login DATETIME,
security_phrase_content TEXT,
security_phrase_iv TEXT,
security_phrase_tag TEXT,
security_phrase_downloaded_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
@@ -93,6 +97,83 @@ CREATE TABLE IF NOT EXISTS user_group_permissions (
);
`;
const createPermissionSectionsTable = `
CREATE TABLE IF NOT EXISTS permission_sections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
has_navigation_flag INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`;
const createPermissionGroupsTable = `
CREATE TABLE IF NOT EXISTS permission_groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
section_id INTEGER NOT NULL,
key TEXT NOT NULL,
title TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(section_id, key),
FOREIGN KEY (section_id) REFERENCES permission_sections(id) ON DELETE CASCADE
);
`;
const createPermissionItemsTable = `
CREATE TABLE IF NOT EXISTS permission_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
section_id INTEGER NOT NULL,
group_id INTEGER,
key TEXT NOT NULL UNIQUE,
label TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
default_level TEXT NOT NULL,
available_levels TEXT NOT NULL,
is_required INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (section_id) REFERENCES permission_sections(id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES permission_groups(id) ON DELETE SET NULL
);
`;
const createPermissionDependenciesTable = `
CREATE TABLE IF NOT EXISTS permission_dependencies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
permission_id INTEGER NOT NULL,
depends_on_permission_id INTEGER NOT NULL,
required_level TEXT DEFAULT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (permission_id) REFERENCES permission_items(id) ON DELETE CASCADE,
FOREIGN KEY (depends_on_permission_id) REFERENCES permission_items(id) ON DELETE CASCADE,
UNIQUE(permission_id, depends_on_permission_id)
);
`;
const createPermissionDependenciesIndex = `
CREATE INDEX IF NOT EXISTS idx_permission_dependencies_required
ON permission_dependencies (permission_id, depends_on_permission_id);
`;
const createGroupPermissionValuesTable = `
CREATE TABLE IF NOT EXISTS group_permission_values (
group_id INTEGER NOT NULL,
permission_id INTEGER NOT NULL,
level TEXT NOT NULL,
effective_level TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (group_id, permission_id),
FOREIGN KEY (group_id) REFERENCES user_groups(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permission_items(id) ON DELETE CASCADE
);
`;
const createServersTable = `
CREATE TABLE IF NOT EXISTS servers (
@@ -364,6 +445,549 @@ console.log('✅ permissions table ready');
db.exec(createUserGroupPermissionsTable);
console.log('✅ user_group_permissions table ready');
db.exec(createPermissionSectionsTable);
console.log('✅ permission_sections table ready');
db.exec(createPermissionGroupsTable);
console.log('✅ permission_groups table ready');
db.exec(createPermissionItemsTable);
console.log('✅ permission_items table ready');
db.exec(createPermissionDependenciesTable);
db.exec(createPermissionDependenciesIndex);
console.log('✅ permission_dependencies table ready');
db.exec(createGroupPermissionValuesTable);
console.log('✅ group_permission_values table ready');
const permissionsSeeded = () => {
try {
const row = db.prepare('SELECT COUNT(*) as count FROM permission_sections').get();
return row?.count > 0;
} catch (err) {
return false;
}
};
const seedPermissions = () => {
if (permissionsSeeded()) {
console.log('️ permission structure already seeded');
return;
}
const insertSection = db.prepare(`
INSERT INTO permission_sections (key, title, sort_order, has_navigation_flag)
VALUES (@key, @title, @sort_order, @has_navigation_flag)
`);
const insertGroup = db.prepare(`
INSERT INTO permission_groups (section_id, key, title, sort_order)
VALUES (@section_id, @key, @title, @sort_order)
`);
const insertItem = db.prepare(`
INSERT INTO permission_items (
section_id,
group_id,
key,
label,
sort_order,
default_level,
available_levels,
is_required
) VALUES (
@section_id,
@group_id,
@key,
@label,
@sort_order,
@default_level,
@available_levels,
@is_required
)
`);
const insertDependency = db.prepare(`
INSERT INTO permission_dependencies (permission_id, depends_on_permission_id, required_level)
VALUES (@permission_id, @depends_on_permission_id, @required_level)
`);
const sections = [
{
key: 'stacks',
title: 'Stacks',
sortOrder: 0,
hasNavigation: 0,
groups: [],
items: [
{
key: 'stacks-redeploy-single',
label: 'Redeploy einzeln',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: []
},
{
key: 'stacks-redeploy-selection',
label: 'Redeploy Auswahl',
sortOrder: 1,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: []
},
{
key: 'stacks-redeploy-all',
label: 'Redeploy Alle',
sortOrder: 2,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: []
}
]
},
{
key: 'logs',
title: 'Logs',
sortOrder: 1,
hasNavigation: 1,
groups: [],
items: [
{
key: 'logs-access',
label: 'Bereich & Navigation',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 1,
dependencies: []
},
{
key: 'logs-export',
label: 'Logs Exportieren',
sortOrder: 1,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'logs-access',
requiredLevel: '!=none'
}
]
},
{
key: 'logs-delete',
label: 'Logs löschen',
sortOrder: 2,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'logs-access',
requiredLevel: '!=none'
}
]
}
]
},
{
key: 'users',
title: 'Benutzer',
sortOrder: 2,
hasNavigation: 1,
groups: [],
items: [
{
key: 'users-access',
label: 'Bereich & Navigation',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 1,
dependencies: []
},
{
key: 'users-edit',
label: 'Benutzer bearbeiten',
sortOrder: 1,
defaultLevel: 'read',
levels: ['full', 'read'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'users-access',
requiredLevel: '!=none'
}
]
},
{
key: 'users-delete',
label: 'Benutzer löschen',
sortOrder: 2,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'users-access',
requiredLevel: '!=none'
}
]
},
{
key: 'users-security-phrase',
label: 'Sicherheitsschlüssel',
sortOrder: 3,
defaultLevel: 'none',
levels: ['full', 'read', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'users-access',
requiredLevel: '!=none'
}
]
}
]
},
{
key: 'user-groups',
title: 'Benutzergruppen',
sortOrder: 3,
hasNavigation: 1,
groups: [],
items: [
{
key: 'user-groups-access',
label: 'Bereich & Navigation',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 1,
dependencies: []
},
{
key: 'user-groups-edit',
label: 'Benutzergruppen bearbeiten',
sortOrder: 1,
defaultLevel: 'read',
levels: ['full', 'read'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'user-groups-access',
requiredLevel: '!=none'
}
]
},
{
key: 'user-groups-delete',
label: 'Benutzergruppen löschen',
sortOrder: 2,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'user-groups-access',
requiredLevel: '!=none'
}
]
}
]
},
{
key: 'maintenance',
title: 'Wartung',
sortOrder: 4,
hasNavigation: 1,
groups: [
{
key: 'maintenance-server-group',
title: 'Server & Endpoints',
sortOrder: 0,
items: [
{
key: 'maintenance-server-manage',
label: 'Server/Endpoint-Sektion',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'read', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
}
]
},
{
key: 'maintenance-server-delete',
label: 'Server/Endpoint löschen',
sortOrder: 1,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
},
{
dependsOnKey: 'maintenance-server-manage',
requiredLevel: '!=none'
}
]
}
]
},
{
key: 'maintenance-portainer-group',
title: 'Portainer',
sortOrder: 1,
items: [
{
key: 'maintenance-portainer',
label: 'Portainer-Sektion',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
}
]
},
{
key: 'maintenance-ssh-update',
label: 'SSH/Update-Skript',
sortOrder: 1,
defaultLevel: 'none',
levels: ['full', 'read', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
},
{
dependsOnKey: 'maintenance-portainer',
requiredLevel: '!=none'
}
]
},
{
key: 'maintenance-update',
label: 'Update durchführen',
sortOrder: 2,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
},
{
dependsOnKey: 'maintenance-portainer',
requiredLevel: '!=none'
}
]
}
]
},
{
key: 'maintenance-duplicates-group',
title: 'Doppelte Stacks',
sortOrder: 2,
items: [
{
key: 'maintenance-duplicates',
label: 'Doppelte Stacks',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'read', 'none'],
isRequired: 0,
dependencies: [
{
dependsOnKey: 'maintenance-access',
requiredLevel: '!=none'
}
]
}
]
}
],
items: [
{
key: 'maintenance-access',
label: 'Bereich & Navigation',
sortOrder: 0,
defaultLevel: 'none',
levels: ['full', 'none'],
isRequired: 1,
dependencies: []
}
]
}
];
const itemKeyToId = new Map();
const insertPermissions = db.transaction(() => {
sections.forEach((section) => {
const sectionResult = insertSection.run({
key: section.key,
title: section.title,
sort_order: section.sortOrder,
has_navigation_flag: section.hasNavigation ? 1 : 0
});
const sectionId = sectionResult.lastInsertRowid;
const sectionItems = section.items ?? [];
sectionItems.forEach((item, index) => {
const itemResult = insertItem.run({
section_id: sectionId,
group_id: null,
key: item.key,
label: item.label,
sort_order: item.sortOrder ?? index,
default_level: item.defaultLevel,
available_levels: JSON.stringify(item.levels),
is_required: item.isRequired ? 1 : 0
});
itemKeyToId.set(item.key, itemResult.lastInsertRowid);
});
const groups = section.groups ?? [];
groups.forEach((group, groupIdx) => {
const groupResult = insertGroup.run({
section_id: sectionId,
key: group.key,
title: group.title,
sort_order: group.sortOrder ?? groupIdx
});
const groupId = groupResult.lastInsertRowid;
const groupItems = group.items ?? [];
groupItems.forEach((item, itemIdx) => {
const itemResult = insertItem.run({
section_id: sectionId,
group_id: groupId,
key: item.key,
label: item.label,
sort_order: item.sortOrder ?? itemIdx,
default_level: item.defaultLevel,
available_levels: JSON.stringify(item.levels),
is_required: item.isRequired ? 1 : 0
});
itemKeyToId.set(item.key, itemResult.lastInsertRowid);
});
});
});
sections.forEach((section) => {
const collectDependencies = (items = []) => {
items.forEach((item) => {
if (!item.dependencies || !item.dependencies.length) {
return;
}
const permissionId = itemKeyToId.get(item.key);
item.dependencies.forEach((dependency) => {
const dependsId = itemKeyToId.get(dependency.dependsOnKey);
if (!dependsId) {
console.warn(`⚠️ dependency target ${dependency.dependsOnKey} not found for ${item.key}`);
return;
}
insertDependency.run({
permission_id: permissionId,
depends_on_permission_id: dependsId,
required_level: dependency.requiredLevel ?? null
});
});
});
};
collectDependencies(section.items);
(section.groups ?? []).forEach((group) => collectDependencies(group.items));
});
});
insertPermissions();
console.log('✅ permission structure seeded');
};
seedPermissions();
const ensureUserSecurityPhraseColumns = () => {
const columns = db.prepare('PRAGMA table_info(users)').all();
const columnNames = new Set(columns.map((column) => column.name));
const addColumnIfMissing = (name, sql) => {
if (!columnNames.has(name)) {
db.exec(sql);
}
};
addColumnIfMissing('security_phrase_content', 'ALTER TABLE users ADD COLUMN security_phrase_content TEXT');
addColumnIfMissing('security_phrase_iv', 'ALTER TABLE users ADD COLUMN security_phrase_iv TEXT');
addColumnIfMissing('security_phrase_tag', 'ALTER TABLE users ADD COLUMN security_phrase_tag TEXT');
addColumnIfMissing('security_phrase_downloaded_at', 'ALTER TABLE users ADD COLUMN security_phrase_downloaded_at DATETIME');
};
ensureUserSecurityPhraseColumns();
const ensurePermissionDefaultLevels = () => {
const desiredDefaults = [
{ key: 'stacks-redeploy-single', defaultLevel: 'none' },
{ key: 'stacks-redeploy-selection', defaultLevel: 'none' },
{ key: 'stacks-redeploy-all', defaultLevel: 'none' },
{ key: 'logs-access', defaultLevel: 'none' },
{ key: 'logs-export', defaultLevel: 'none' },
{ key: 'logs-delete', defaultLevel: 'none' },
{ key: 'users-access', defaultLevel: 'none' },
{ key: 'users-edit', defaultLevel: 'read' },
{ key: 'users-delete', defaultLevel: 'none' },
{ key: 'users-security-phrase', defaultLevel: 'none' },
{ key: 'user-groups-access', defaultLevel: 'none' },
{ key: 'user-groups-edit', defaultLevel: 'read' },
{ key: 'user-groups-delete', defaultLevel: 'none' },
{ key: 'maintenance-access', defaultLevel: 'none' },
{ key: 'maintenance-server-manage', defaultLevel: 'none' },
{ key: 'maintenance-server-delete', defaultLevel: 'none' },
{ key: 'maintenance-portainer', defaultLevel: 'none' },
{ key: 'maintenance-ssh-update', defaultLevel: 'none' },
{ key: 'maintenance-update', defaultLevel: 'none' },
{ key: 'maintenance-duplicates', defaultLevel: 'none' }
];
const updateDefaultLevel = db.prepare(`
UPDATE permission_items
SET default_level = @default_level
WHERE key = @key AND default_level != @default_level
`);
db.transaction(() => {
desiredDefaults.forEach(({ key, defaultLevel }) => {
updateDefaultLevel.run({ key, default_level: defaultLevel });
});
})();
};
ensurePermissionDefaultLevels();
db.exec(
"DELETE FROM group_permission_values WHERE group_id IN (SELECT id FROM user_groups WHERE lower(name) = 'superuser')"
);
db.exec(createServersTable);
console.log('✅ servers table ready');