mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 09:35:39 +00:00
a9e217c165
Go server: - mergeAdminTagsIntoAB: strip banned/deleted peers from AB data - handleClientGroupList: exclude banned peers from tag groups - handleClientPeersList: add device_name fallback to peer ID, add online field - handleGetPeer/handleListPeers: return status as int (1/0) with status_text - handleUsersWithClientFallback: only return users with assigned devices Node.js console: - mergeAddressBookData: filter banned devices from AB merge - buildSyncedAddressBook: set includeDevices=false to prevent ghost AB entries - normalisePeer: use status_text fallback for status_tier This commit was made possible thanks to Insolve.
201 lines
5.7 KiB
JavaScript
201 lines
5.7 KiB
JavaScript
/**
|
|
* RustDesk address book sync helpers.
|
|
*
|
|
* The web panel stores device tags and folders separately. RustDesk address
|
|
* books only own explicit peer tags; BetterDesk folders are exposed through the
|
|
* RustDesk device-group API. Folder names must not be used to infer or remove
|
|
* address book tags because users can intentionally use the same label for both.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const MAX_TAG_LENGTH = 50;
|
|
|
|
function sanitizeTag(value) {
|
|
if (typeof value !== 'string') return '';
|
|
return value
|
|
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
|
|
.trim()
|
|
.slice(0, MAX_TAG_LENGTH);
|
|
}
|
|
|
|
function uniquePush(list, seen, value) {
|
|
const tag = sanitizeTag(value);
|
|
if (!tag || seen.has(tag)) return;
|
|
seen.add(tag);
|
|
list.push(tag);
|
|
}
|
|
|
|
function normalizeTags(value) {
|
|
if (!value) return [];
|
|
|
|
let raw = value;
|
|
if (typeof raw === 'string') {
|
|
const trimmed = raw.trim();
|
|
if (!trimmed) return [];
|
|
if (trimmed.startsWith('[')) {
|
|
try {
|
|
raw = JSON.parse(trimmed);
|
|
} catch (_) {
|
|
raw = trimmed.split(',');
|
|
}
|
|
} else {
|
|
raw = trimmed.split(',');
|
|
}
|
|
}
|
|
|
|
if (!Array.isArray(raw)) return [];
|
|
|
|
const tags = [];
|
|
const seen = new Set();
|
|
for (const item of raw) {
|
|
uniquePush(tags, seen, String(item || ''));
|
|
}
|
|
return tags;
|
|
}
|
|
|
|
function filterFolderTags(tags) {
|
|
return normalizeTags(tags);
|
|
}
|
|
|
|
function parseAddressBookData(data) {
|
|
let parsed = {};
|
|
|
|
if (data && typeof data === 'object' && !Buffer.isBuffer(data)) {
|
|
parsed = { ...data };
|
|
} else if (typeof data === 'string' && data.trim()) {
|
|
try {
|
|
parsed = JSON.parse(data);
|
|
} catch (_) {
|
|
parsed = {};
|
|
}
|
|
}
|
|
|
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
parsed = {};
|
|
}
|
|
|
|
parsed.peers = Array.isArray(parsed.peers) ? parsed.peers : [];
|
|
parsed.tags = normalizeTags(parsed.tags);
|
|
|
|
return parsed;
|
|
}
|
|
|
|
function getDeviceTags(device) {
|
|
return normalizeTags(device && device.tags);
|
|
}
|
|
|
|
function mergePeerFields(existing, device, tags) {
|
|
const peer = existing && typeof existing === 'object' && !Array.isArray(existing)
|
|
? existing
|
|
: {};
|
|
|
|
peer.id = String(peer.id || device.id || '');
|
|
if (!peer.username && (device.username || device.user)) peer.username = String(device.username || device.user);
|
|
if (!peer.hostname && device.hostname) peer.hostname = String(device.hostname);
|
|
if (!peer.alias && (device.display_name || device.note)) peer.alias = String(device.display_name || device.note);
|
|
if (!peer.platform && (device.platform || device.os)) peer.platform = String(device.platform || device.os);
|
|
peer.tags = tags;
|
|
|
|
return peer;
|
|
}
|
|
|
|
function mergeAddressBookData(data, options = {}) {
|
|
const ab = parseAddressBookData(data);
|
|
const devices = Array.isArray(options.devices) ? options.devices : [];
|
|
const includeDevices = options.includeDevices !== false;
|
|
|
|
// Issue #138: build set of banned/deleted device IDs to strip from AB
|
|
const bannedIds = new Set();
|
|
for (const device of devices) {
|
|
const id = String(device && device.id || '').trim();
|
|
if (!id) continue;
|
|
if (device.banned || device.soft_deleted) {
|
|
bannedIds.add(id);
|
|
}
|
|
}
|
|
|
|
ab.tags = normalizeTags(ab.tags);
|
|
const globalSeen = new Set(ab.tags);
|
|
|
|
const peerById = new Map();
|
|
// Filter out banned/deleted peers from existing AB data
|
|
ab.peers = ab.peers.filter(peer => {
|
|
if (!peer || typeof peer !== 'object') return false;
|
|
const id = String(peer.id || '').trim();
|
|
if (!id) return false;
|
|
if (bannedIds.has(id)) return false; // strip banned
|
|
return true;
|
|
});
|
|
for (const peer of ab.peers) {
|
|
const id = String(peer.id || '').trim();
|
|
peer.tags = normalizeTags(peer.tags);
|
|
peerById.set(id, peer);
|
|
for (const tag of peer.tags) {
|
|
uniquePush(ab.tags, globalSeen, tag);
|
|
}
|
|
}
|
|
|
|
for (const device of devices) {
|
|
const id = String(device && device.id || '').trim();
|
|
if (!id) continue;
|
|
|
|
const existing = peerById.get(id);
|
|
if (!existing && !includeDevices) continue;
|
|
|
|
const mergedTags = normalizeTags(existing && existing.tags);
|
|
const tagSeen = new Set(mergedTags);
|
|
for (const tag of getDeviceTags(device)) {
|
|
uniquePush(mergedTags, tagSeen, tag);
|
|
uniquePush(ab.tags, globalSeen, tag);
|
|
}
|
|
|
|
const peer = mergePeerFields(existing, device, mergedTags);
|
|
if (!existing) {
|
|
ab.peers.push(peer);
|
|
peerById.set(id, peer);
|
|
}
|
|
}
|
|
|
|
return JSON.stringify(ab);
|
|
}
|
|
|
|
function collectVisibleTags(devices, folders, assignments) {
|
|
const tags = [];
|
|
const seen = new Set();
|
|
|
|
for (const device of Array.isArray(devices) ? devices : []) {
|
|
for (const tag of getDeviceTags(device)) {
|
|
uniquePush(tags, seen, tag);
|
|
}
|
|
}
|
|
|
|
return tags.sort((a, b) => a.localeCompare(b));
|
|
}
|
|
|
|
function collectPeerTagUpdates(data, options = {}) {
|
|
const ab = parseAddressBookData(data);
|
|
const updates = [];
|
|
const seen = new Set();
|
|
|
|
for (const peer of ab.peers) {
|
|
if (!peer || typeof peer !== 'object') continue;
|
|
const id = String(peer.id || '').trim();
|
|
if (!id || seen.has(id)) continue;
|
|
if (!Object.prototype.hasOwnProperty.call(peer, 'tags')) continue;
|
|
seen.add(id);
|
|
updates.push({ id, tags: normalizeTags(peer.tags) });
|
|
}
|
|
|
|
return updates;
|
|
}
|
|
|
|
module.exports = {
|
|
normalizeTags,
|
|
parseAddressBookData,
|
|
filterFolderTags,
|
|
mergeAddressBookData,
|
|
collectVisibleTags,
|
|
collectPeerTagUpdates
|
|
};
|