import { PartialProfileGroup, ProfileGroup } from 'tabby-core'; import { TranslatableMessage } from './i18nMessage'; /** * Sharing a folder as JSON: what goes out, what is stripped on the way, and how * what comes back in is read. * * Kept out of the tree component on purpose. Serialising, purging and parsing * are pure functions over plain objects — they need neither Angular nor the * config — and the component is already 3800 lines. The snippet library made * the same move for the same reason, one refactor too late. * * **The purge is a security question, not a convenience one.** Read * `purgeOptions()` before adding a field to any of the lists below, and * `PROFILE_OPTION_WHITELISTS` before adding a profile type: what a type does * *not* list is dropped, not merely left unstripped — a field a future Tabby * adds, or a type this plugin has never heard of, is refused rather than * trusted. That whitelist is checked on both ends: a profile whose options * this plugin cannot vouch for does not leave either. */ export declare const SHARE_FORMAT = "tabby-better-sidebar/group"; export declare const SHARE_VERSION = 1; /** * How much is taken out. * * - `secrets` — passwords, login scripts and vault references. Everything else * travels, so the export pastes back as the folder it came from. This is the * one for moving between one's own machines. * - `credentials` — the above, plus the username, the private keys, the * route to the host (jump host, proxies, forwarded ports) and the remote * start directory. The host and port stay: a structure with no host pastes * into something nobody can connect to. */ export type PurgeLevel = 'secrets' | 'credentials'; /** What a purge took out, counted so it can be said rather than guessed at. */ export interface PurgeReport { /** Profiles that carried a `password`. */ passwords: number; /** Login scripts removed, summed over every profile. */ scripts: number; /** `vault://` private key references — meaningless on any other machine. */ vaultKeys: number; /** Private key paths removed (level `credentials` only). */ privateKeys: number; /** Usernames, jump hosts, proxies, forwarded ports and remote start directories (level `credentials` only). */ credentials: number; /** Fields caught by the name heuristic rather than by an explicit rule. */ suspicious: number; /** Fields that launch a local process on connect — `proxyCommand` — removed at every level, like `scripts`. */ commands: number; /** Options present on a profile or `defaults` block but absent from that type's whitelist. */ unknownOptions: number; /** Profiles, or `defaults` blocks, of a type this plugin does not have a whitelist for — dropped whole. */ rejectedTypes: number; } export interface SharedProfile { name?: string; type?: string; icon?: string; color?: string; weight?: number; options?: Record; } export interface SharedGroup { name?: string; icon?: string; color?: string; /** Merged by Tabby into *every profile of the folder* — purged like any options block (piège #62). */ defaults?: Record; profiles: SharedProfile[]; children: SharedGroup[]; } export interface SharePayload { format: string; version: number; /** * What the export took out, totalled over the whole tree. * * On the way back in this is what the payload *claims*, and it is used for * one thing only: telling whoever pastes what they will have to re-enter. * It guards nothing — see `strippedOnImport`. */ removed: PurgeReport; purge: PurgeLevel; /** * What the purge had to take out *again* while reading the payload. * * Anything but zero means the JSON still carried a secret its own header * said had been removed — a hand-edited or foreign payload. Nothing breaks * (it has just been stripped), but it is worth saying. */ strippedOnImport?: PurgeReport; group: SharedGroup; } export declare function emptyReport(): PurgeReport; /** * A folder and everything under it. * * `defaults` travels — Tabby merges it into every profile of the folder, so * leaving it behind strips the pasted profiles of what they inherited (that is * piège #62, met once already) — but it is an options block like any other and * gets the same purge. A folder-wide `defaults.ssh.password` is a real thing. * * Reads the tree it is handed rather than fetching one: the caller holds an * unfiltered snapshot, and a workspace-filtered tree would quietly export a * subset of the folder. */ export declare function shareGroup(group: PartialProfileGroup, allGroups: PartialProfileGroup[], level: PurgeLevel, report: PurgeReport, depth?: number): SharedGroup; export declare function buildPayload(group: PartialProfileGroup, allGroups: PartialProfileGroup[], level: PurgeLevel): SharePayload; export interface ParseResult { payload?: SharePayload; /** * Why it was refused, as a message key and its params rather than an * already-shown string — this module has no injector access, translation * happens at the call site. Set when `payload` is not. */ error?: TranslatableMessage; } /** * Reads what the clipboard holds, and refuses anything it does not recognise. * * **The purge runs again here, on the way in.** The payload says what was taken * out at export time, and that claim is worth exactly nothing: the JSON is text * from the clipboard, editable by hand and possibly written by someone else. So * nothing trusts `removed`, it is re-derived — a payload with a `password` left * in it loses it here, whatever its header says. */ export declare function parsePayload(text: string): ParseResult; /** Whether a report has anything to say. */ export declare function isEmptyReport(report: PurgeReport | undefined): boolean; /** Folders and profiles in a shared tree, for the notice and the paste modal. */ export declare function countPayload(group: SharedGroup): { folders: number; profiles: number; }; /** * The purge, as a list of clauses ready to be translated and joined — * "in one sentence" used to be this function's own job, but it has no * injector access, so it hands back the parts instead and the join happens * where `this.i18n` is reachable (`sidebarTree.component.ts`). * * Written for the person on the other end: what is missing and has to be * re-entered, not what the algorithm did. Empty when nothing was taken out. */ export declare function describePurge(report: PurgeReport): TranslatableMessage[];