' +
- '
' + phIcon('lock') + ' Privacy Notice
' +
- '
' +
- 'Effective date: ' + txt(cfg.effectiveDate) + '
' +
- 'Data controller: ' + controller + '
' +
- 'Privacy contact: ' + contactInline +
- '
' +
- '
This CoreScope deployment provides status information and analysis for a ' +
- 'community-operated MeshCore radio network. It receives packet and reception data ' +
- 'from participating observer nodes and makes selected information available through ' +
- 'this website and its API.
';
-
- if (txt(cfg.dpoName) || txt(cfg.dpoContact)) {
- html += section('user-circle', 'Data protection officer',
- '
' + [txt(cfg.dpoName), txt(cfg.dpoContact)].filter(Boolean).join('
') + '
');
- }
-
- // What data is processed. This list describes CoreScope's actual
- // pipeline: radio traffic AND the reception/observer metadata CoreScope
- // itself produces, plus derived analytics. Phrased as "may process,
- // depending on configuration" because several categories are opt-in.
- html += section('broadcast', 'What data this site processes',
- '
Depending on this deployment’s configuration, CoreScope may process:
' +
- '
' +
- '- Node information advertised over the radio network: public keys, node names, roles and advertised positions.
' +
- '- Packet metadata: timestamps, packet types, routing paths and hop information.
' +
- '- Reception metadata produced by observer nodes: which observer received a packet, and the associated SNR/RSSI measurements.
' +
- '- Observer identity, status and operational metrics.
' +
- '- Derived information generated by this site: distances, routes, coverage estimates, node health and network statistics.
' +
- '- Optional mobile client reception data, which may include the reception position reported by the client.
' +
- '- Encrypted group or channel packets, stored as packet records.
' +
- '- Message content from channels whose keys are known to this deployment — see below.
' +
- '
' +
- '
A node name or advertised position may identify or reveal information about its ' +
- 'operator. Do not include personal information in node names, positions or channel ' +
- 'messages unless you intend it to be publicly visible.
');
-
- html += section('target', 'Purpose of processing', paras(cfg.purposesText));
-
- // Legal basis: the operator's structured choice plus their own wording.
- // The software never asserts a basis and never infers one from prose.
- var basisLabel = {
- consent: 'Consent',
- contract: 'Performance of a contract',
- legal_obligation: 'Legal obligation',
- vital_interests: 'Vital interests',
- public_task: 'Public task',
- legitimate_interests: 'Legitimate interests',
- }[String(cfg.legalBasisType || '').trim()] || txt(cfg.legalBasisType);
- var basisBody = '
' + escapeHtml(basisLabel) + '
' + paras(cfg.legalBasisText);
- if (String(cfg.legalBasisType || '').trim() === 'legitimate_interests') {
- basisBody += paras(cfg.legitimateInterestsText);
- }
- basisBody += '
The lawful basis and its description are stated by the operator of this deployment.
';
- html += section('scales', 'Legal basis', basisBody);
-
- html += section('arrow-down', 'Sources of the data', paras(cfg.dataSourcesText));
- html += section('users', 'Who can receive the data', paras(cfg.recipientsText));
-
- html += section('clock', 'Retention',
- paras(cfg.retentionText) +
- '
Different categories may have different retention rules. Moving a node ' +
- 'to an inactive-node table, marking an observer inactive or hiding a node from ' +
- 'dashboard and API views does not necessarily delete its historical packet or ' +
- 'observation data.
');
-
- // Messages. Verified against the code: only group/channel payloads are
- // ever decrypted, and only with keys this deployment holds. Direct
- // message CONTENT is not decrypted -- but the surrounding metadata is
- // still processed. Stored ciphertext is retained, so a packet that is
- // unreadable today could be decoded later if a key becomes available.
- html += section('chats', 'Channel and direct messages',
- '
Messages on channels whose keys are available to this deployment may be decoded ' +
- 'and published. Encrypted group or channel packets are stored as received, so a ' +
- 'packet that cannot be read today may become readable later if a corresponding key ' +
- 'becomes available to this deployment.
' +
- '
Direct-message content is not decrypted by CoreScope. Packet, route and reception ' +
- 'metadata associated with direct messages — such as timestamps, packet type, routing ' +
- 'path and which observers received it — may nevertheless be stored and displayed.
' +
- '
Avoid transmitting personal or sensitive information on shared channels.
');
-
- html += section('browser', 'Storage in your browser', paras(cfg.browserStorageText));
- html += section('file-text', 'Server and proxy logs', paras(cfg.serverLogsText));
- html += section('globe', 'External services', paras(cfg.thirdPartyServicesText));
- html += section('airplane', 'International transfers', paras(cfg.internationalTransfersText));
-
- // Self-service hiding: only offered when this deployment actually has
- // hide prefixes configured, and always described as a visibility filter
- // -- never as removal from the radio network or as deletion.
- var prefixes = Array.isArray(cfg.hiddenNamePrefixes) ? cfg.hiddenNamePrefixes.filter(function (x) {
- return typeof x === 'string' && x.trim() !== '';
- }) : [];
- var hiddenBody;
- if (prefixes.length) {
- var rendered = prefixes.map(function (x) {
- return '
' + escapeHtml(x) + '';
- }).join(prefixes.length === 2 ? ' or ' : ', ');
- hiddenBody =
- '
This deployment hides nodes whose name begins with ' + rendered +
- ' from selected dashboard and API views.
';
- } else {
- hiddenBody =
- '
This deployment has no name-prefix hiding configured.
';
- }
- hiddenBody +=
- '
Prefix hiding is a visibility filter on this site’s dashboard and API only. ' +
- 'It does not remove a node from the radio network — other listeners still receive its ' +
- 'transmissions — and it does not by itself delete stored packets, observations or ' +
- 'derived analytics.
';
- html += section('eye-slash', 'Hidden nodes', hiddenBody);
-
- html += section('cpu', 'Automated decision-making', paras(cfg.automatedDecisionMakingText));
-
- html += section('info', 'Changes to this notice',
- '
This notice may be updated when the deployment, its configuration or its ' +
- 'data-processing practices change. The effective date shown at the top identifies the ' +
- 'current version.
');
-
- html += '
';
- container.innerHTML = html;
- }
-
registerPage('privacy', {
init: function (container) {
- container.innerHTML =
- '