mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 17:40:46 -04:00
legacy importer in admin page aswell as setup.
This commit is contained in:
@@ -11,6 +11,11 @@ const {
|
||||
applyCommittedConfiguration,
|
||||
rootSchema,
|
||||
} = require('../../configuration');
|
||||
const {
|
||||
MAX_CONFIGURATION_FILE_BYTES,
|
||||
parseConfigurationFile,
|
||||
buildSecretOperationsForImport,
|
||||
} = require('../../configuration/configurationFileImporter');
|
||||
const { getRole } = require('../roleService');
|
||||
|
||||
const PASSWORD_CONFIRMATION_WINDOW_MS = 5 * 60 * 1000;
|
||||
@@ -34,6 +39,18 @@ function actorFor(socket) {
|
||||
return socket?.data?.user?.username || socket.id;
|
||||
}
|
||||
|
||||
function safeUploadedFileName(value) {
|
||||
/*
|
||||
The filename is audit metadata only and is never opened on the server.
|
||||
Removing control characters keeps logs and history readable while
|
||||
retaining the operator-visible name that identifies the imported file.
|
||||
*/
|
||||
return String(value || 'uploaded-config.yaml')
|
||||
.replace(/[\u0000-\u001f\u007f]/g, '')
|
||||
.trim()
|
||||
.slice(0, 255) || 'uploaded-config.yaml';
|
||||
}
|
||||
|
||||
function errorPayload(error) {
|
||||
return {
|
||||
error: error.message,
|
||||
@@ -102,6 +119,37 @@ io.on('connection', (socket) => {
|
||||
return { revision, application, snapshot: buildAdminSnapshot() };
|
||||
});
|
||||
|
||||
ackHandler(socket, 'adminConfig:importConfigurationFile', requireRecentPassword, async (payload) => {
|
||||
const yamlText = String(payload.yaml || '');
|
||||
if (!yamlText || Buffer.byteLength(yamlText, 'utf8') > MAX_CONFIGURATION_FILE_BYTES) {
|
||||
throw new Error('The YAML configuration file must be present and no larger than 1 MiB.');
|
||||
}
|
||||
|
||||
/*
|
||||
Parsing deliberately excludes administrators on an initialized server.
|
||||
Configuration is still filtered to today's schema and strictly
|
||||
validated, then committed through the ordinary optimistic update path so
|
||||
missing secrets survive and explicitly supplied secrets replace or clear
|
||||
their current values.
|
||||
*/
|
||||
const parsed = parseConfigurationFile(yamlText, { includeAdministrators: false });
|
||||
const fileName = safeUploadedFileName(payload.fileName);
|
||||
const revision = database.updateConfiguration({
|
||||
value: parsed.config,
|
||||
expectedRevision: payload.expectedRevision,
|
||||
secretOperations: buildSecretOperationsForImport(parsed),
|
||||
actor: actorFor(socket),
|
||||
source: `admin-yaml:${fileName}`,
|
||||
});
|
||||
const application = await applyCommittedConfiguration();
|
||||
return {
|
||||
revision,
|
||||
application,
|
||||
ignoredAdministratorCount: parsed.uploadedAdministratorCount,
|
||||
snapshot: buildAdminSnapshot(),
|
||||
};
|
||||
});
|
||||
|
||||
ackHandler(socket, 'adminConfig:restoreRevision', requireRecentPassword, async (payload) => {
|
||||
const revision = database.restoreConfigurationRevision({
|
||||
revision: payload.revision,
|
||||
|
||||
@@ -6,10 +6,12 @@ const bcrypt = require('bcrypt');
|
||||
const io = require('../../globals/io');
|
||||
const logger = require('../../globals/logger').child('setupService');
|
||||
const { getConfigurationDatabase, applyCommittedConfiguration } = require('../../configuration');
|
||||
const { importConfigurationFile } = require('../../configuration/configurationFileImporter');
|
||||
const {
|
||||
MAX_CONFIGURATION_FILE_BYTES,
|
||||
importConfigurationFile,
|
||||
} = require('../../configuration/configurationFileImporter');
|
||||
const { createSetupCodeFile } = require('./setupCodeFile');
|
||||
|
||||
const MAX_CONFIGURATION_FILE_BYTES = 1024 * 1024;
|
||||
const database = getConfigurationDatabase();
|
||||
const setupCodeFile = createSetupCodeFile();
|
||||
let setupNoticeLogged = false;
|
||||
|
||||
Reference in New Issue
Block a user