Files
op-packages/luci-app-homeproxy/root/etc/homeproxy/scripts/node_references.uc
T

363 lines
11 KiB
Ucode

'use strict';
function isEmpty(value) {
return !value || value === 'nil' || (type(value) in ['array', 'object'] && length(value) === 0);
}
function toArray(value) {
if (type(value) === 'array')
return value;
else if (isEmpty(value))
return [];
return [ value ];
}
function removeListValue(uci, config, section, option, value) {
let values = toArray(uci.get(config, section, option)),
filtered = [];
for (let item in values)
if (item !== value)
push(filtered, item);
if (length(filtered))
uci.set(config, section, option, filtered);
else if (length(values))
uci.delete(config, section, option);
}
function addReference(refs, entry) {
push(refs, entry);
}
function addCleanupChange(changes, node_id, scope, section, option, action, value) {
push(changes, {
node_id: node_id,
scope: scope,
section: section,
option: option,
action: action,
value: value
});
}
function normalizeUniqueNodeIds(node_ids) {
let seen = {},
unique_ids = [];
if (type(node_ids) !== 'array')
return unique_ids;
for (let node_id in node_ids)
if (!seen[node_id] && !isEmpty(node_id)) {
seen[node_id] = true;
push(unique_ids, node_id);
}
return unique_ids;
}
export function collect_node_references(uci, config, node_id) {
let refs = [];
if (isEmpty(node_id))
return refs;
if (uci.get(config, 'config', 'main_node') === node_id)
addReference(refs, {
scope: 'main_node',
section: 'config',
option: 'main_node',
label: 'Main node'
});
if (uci.get(config, 'config', 'main_udp_node') === node_id)
addReference(refs, {
scope: 'main_udp_node',
section: 'config',
option: 'main_udp_node',
label: 'Main UDP node'
});
if (~index(toArray(uci.get(config, 'config', 'main_urltest_nodes')), node_id))
addReference(refs, {
scope: 'main_urltest_nodes',
section: 'config',
option: 'main_urltest_nodes',
label: 'Main node / URLTest nodes'
});
if (~index(toArray(uci.get(config, 'config', 'main_udp_urltest_nodes')), node_id))
addReference(refs, {
scope: 'main_udp_urltest_nodes',
section: 'config',
option: 'main_udp_urltest_nodes',
label: 'Main UDP node / URLTest nodes'
});
if (uci.get(config, 'routing', 'default_outbound') === node_id)
addReference(refs, {
scope: 'default_outbound',
section: 'routing',
option: 'default_outbound',
label: 'Routing / Default outbound'
});
uci.foreach(config, 'routing_node', (cfg) => {
const section = cfg['.name'],
label = cfg.label || section;
if (uci.get(config, section, 'node') === node_id)
addReference(refs, {
scope: 'routing_node_node',
section: section,
option: 'node',
label: sprintf('Routing Nodes / %s / Node', label)
});
if (uci.get(config, section, 'outbound') === node_id)
addReference(refs, {
scope: 'routing_node_outbound',
section: section,
option: 'outbound',
label: sprintf('Routing Nodes / %s / Outbound', label)
});
if (uci.get(config, section, 'selector_default') === node_id)
addReference(refs, {
scope: 'routing_node_selector_default',
section: section,
option: 'selector_default',
label: sprintf('Routing Nodes / %s / Default', label)
});
if (~index(toArray(uci.get(config, section, 'urltest_nodes')), node_id))
addReference(refs, {
scope: 'routing_node_urltest_nodes',
section: section,
option: 'urltest_nodes',
label: sprintf('Routing Nodes / %s / URLTest nodes', label)
});
if (~index(toArray(uci.get(config, section, 'selector_nodes')), node_id))
addReference(refs, {
scope: 'routing_node_selector_nodes',
section: section,
option: 'selector_nodes',
label: sprintf('Routing Nodes / %s / Selector nodes', label)
});
});
uci.foreach(config, 'routing_rule', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id)
addReference(refs, {
scope: 'routing_rule_outbound',
section: cfg['.name'],
option: 'outbound',
label: sprintf('Routing Rules / %s / Outbound', cfg.label || cfg['.name'])
});
});
uci.foreach(config, 'dns_server', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id)
addReference(refs, {
scope: 'dns_server_outbound',
section: cfg['.name'],
option: 'outbound',
label: sprintf('DNS Server / %s / Outbound', cfg.label || cfg['.name'])
});
});
uci.foreach(config, 'dns_rule', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id)
addReference(refs, {
scope: 'dns_rule_outbound',
section: cfg['.name'],
option: 'outbound',
label: sprintf('DNS Rules / %s / Outbound', cfg.label || cfg['.name'])
});
});
uci.foreach(config, 'ruleset', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id)
addReference(refs, {
scope: 'ruleset_outbound',
section: cfg['.name'],
option: 'outbound',
label: sprintf('Rule set / %s / Outbound', cfg.label || cfg['.name'])
});
});
return refs;
};
export function cleanup_node_references_for_delete(uci, config, node_id, opts) {
opts = opts || {};
if (isEmpty(node_id))
return { changed: false, changes: [] };
let changed = false,
changes = [],
main_node_fallback = isEmpty(opts.main_node_fallback) ? 'nil' : opts.main_node_fallback,
main_udp_fallback = isEmpty(opts.main_udp_fallback) ? 'same' : opts.main_udp_fallback;
if (uci.get(config, 'config', 'main_node') === node_id) {
uci.set(config, 'config', 'main_node', main_node_fallback);
addCleanupChange(changes, node_id, 'main_node', 'config', 'main_node', 'set', main_node_fallback);
changed = true;
}
if (uci.get(config, 'config', 'main_udp_node') === node_id) {
uci.set(config, 'config', 'main_udp_node', main_udp_fallback);
addCleanupChange(changes, node_id, 'main_udp_node', 'config', 'main_udp_node', 'set', main_udp_fallback);
changed = true;
}
let before_main_urltest = length(toArray(uci.get(config, 'config', 'main_urltest_nodes')));
removeListValue(uci, config, 'config', 'main_urltest_nodes', node_id);
if (length(toArray(uci.get(config, 'config', 'main_urltest_nodes'))) !== before_main_urltest) {
addCleanupChange(changes, node_id, 'main_urltest_nodes', 'config', 'main_urltest_nodes', 'remove', null);
changed = true;
}
if (uci.get(config, 'config', 'main_node') === 'urltest' &&
!length(toArray(uci.get(config, 'config', 'main_urltest_nodes')))) {
uci.set(config, 'config', 'main_node', main_node_fallback);
addCleanupChange(changes, node_id, 'main_node', 'config', 'main_node', 'set', main_node_fallback);
changed = true;
}
let before_main_udp_urltest = length(toArray(uci.get(config, 'config', 'main_udp_urltest_nodes')));
removeListValue(uci, config, 'config', 'main_udp_urltest_nodes', node_id);
if (length(toArray(uci.get(config, 'config', 'main_udp_urltest_nodes'))) !== before_main_udp_urltest) {
addCleanupChange(changes, node_id, 'main_udp_urltest_nodes', 'config', 'main_udp_urltest_nodes', 'remove', null);
changed = true;
}
if (uci.get(config, 'config', 'main_udp_node') === 'urltest' &&
!length(toArray(uci.get(config, 'config', 'main_udp_urltest_nodes')))) {
uci.set(config, 'config', 'main_udp_node', main_udp_fallback);
addCleanupChange(changes, node_id, 'main_udp_node', 'config', 'main_udp_node', 'set', main_udp_fallback);
changed = true;
}
if (uci.get(config, 'routing', 'default_outbound') === node_id) {
uci.set(config, 'routing', 'default_outbound', 'nil');
addCleanupChange(changes, node_id, 'default_outbound', 'routing', 'default_outbound', 'set', 'nil');
changed = true;
}
uci.foreach(config, 'routing_node', (cfg) => {
const section = cfg['.name'];
if (uci.get(config, section, 'node') === node_id) {
uci.delete(config, section, 'node');
addCleanupChange(changes, node_id, 'routing_node_node', section, 'node', 'delete', null);
changed = true;
}
if (uci.get(config, section, 'outbound') === node_id) {
uci.delete(config, section, 'outbound');
addCleanupChange(changes, node_id, 'routing_node_outbound', section, 'outbound', 'delete', null);
changed = true;
}
if (uci.get(config, section, 'selector_default') === node_id) {
uci.delete(config, section, 'selector_default');
addCleanupChange(changes, node_id, 'routing_node_selector_default', section, 'selector_default', 'delete', null);
changed = true;
}
let before_urltest = length(toArray(uci.get(config, section, 'urltest_nodes')));
removeListValue(uci, config, section, 'urltest_nodes', node_id);
if (length(toArray(uci.get(config, section, 'urltest_nodes'))) !== before_urltest) {
addCleanupChange(changes, node_id, 'routing_node_urltest_nodes', section, 'urltest_nodes', 'remove', null);
changed = true;
}
let before_selector = length(toArray(uci.get(config, section, 'selector_nodes')));
removeListValue(uci, config, section, 'selector_nodes', node_id);
if (length(toArray(uci.get(config, section, 'selector_nodes'))) !== before_selector) {
addCleanupChange(changes, node_id, 'routing_node_selector_nodes', section, 'selector_nodes', 'remove', null);
changed = true;
}
});
uci.foreach(config, 'routing_rule', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id) {
uci.set(config, cfg['.name'], 'outbound', 'block-out');
addCleanupChange(changes, node_id, 'routing_rule_outbound', cfg['.name'], 'outbound', 'set', 'block-out');
changed = true;
}
});
uci.foreach(config, 'dns_server', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id) {
uci.set(config, cfg['.name'], 'outbound', 'block-out');
addCleanupChange(changes, node_id, 'dns_server_outbound', cfg['.name'], 'outbound', 'set', 'block-out');
changed = true;
}
});
uci.foreach(config, 'dns_rule', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id) {
uci.set(config, cfg['.name'], 'outbound', 'block-out');
addCleanupChange(changes, node_id, 'dns_rule_outbound', cfg['.name'], 'outbound', 'set', 'block-out');
changed = true;
}
});
uci.foreach(config, 'ruleset', (cfg) => {
if (uci.get(config, cfg['.name'], 'outbound') === node_id) {
uci.set(config, cfg['.name'], 'outbound', 'block-out');
addCleanupChange(changes, node_id, 'ruleset_outbound', cfg['.name'], 'outbound', 'set', 'block-out');
changed = true;
}
});
return {
changed: changed,
changes: changes,
main_node_fallback: main_node_fallback,
main_udp_fallback: main_udp_fallback
};
};
export function remove_subscription_nodes(uci, config, node_ids, opts) {
opts = opts || {};
let unique_ids = normalizeUniqueNodeIds(node_ids),
removed = 0,
changed = false,
changes = [],
main_node_fallback = isEmpty(opts.main_node_fallback) ? 'nil' : opts.main_node_fallback,
main_udp_fallback = isEmpty(opts.main_udp_fallback) ? 'same' : opts.main_udp_fallback;
for (let node_id in unique_ids) {
let cfg = uci.get_all(config, node_id);
if (!cfg || cfg['.type'] !== 'node' || isEmpty(cfg.grouphash))
continue;
const cleanup = cleanup_node_references_for_delete(uci, config, node_id, {
main_node_fallback: main_node_fallback,
main_udp_fallback: main_udp_fallback
});
if (cleanup.changed) {
changed = true;
for (let item in cleanup.changes)
push(changes, item);
}
uci.delete(config, node_id);
removed++;
}
return {
changed: changed,
removed: removed,
changes: changes,
main_node_fallback: main_node_fallback,
main_udp_fallback: main_udp_fallback
};
};