mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-06-10 08:20:13 +00:00
a392ccab6a
- Now the `report` includes recent logs (of verbosity `verbose` even settings is not set to `verbose`). - Updating logs is now debounced to avoid excessive updates during rapid log generation. - Added a `Generate full report for opening the issue with debug info` command to the command palette, which generates a report without opening the settings dialogue.
143 lines
6.4 KiB
TypeScript
143 lines
6.4 KiB
TypeScript
import { REMOTE_COUCHDB, REMOTE_MINIO } from "@lib/common/models/setting.const";
|
|
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
|
|
import { generateCredentialObject } from "@lib/replication/httplib";
|
|
import { parseHeaderValues } from "@lib/common/utils";
|
|
import { requestToCouchDBWithCredentials } from "./utils";
|
|
import { LOG_LEVEL_VERBOSE, Logger } from "@lib/common/logger";
|
|
import { DEFAULT_SETTINGS } from "@lib/common/models/setting.const.defaults";
|
|
import { isCloudantURI } from "@lib/pouchdb/utils_couchdb";
|
|
import { compatGlobal } from "@lib/common/coreEnvFunctions";
|
|
import { manifestVersion, packageVersion } from "@lib/common/coreEnvVars";
|
|
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
|
|
function redactObject(obj: Record<string, any>, dotted: string, redactedValue = "REDACTED") {
|
|
const keys = dotted.split(".");
|
|
let current = obj;
|
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
const key = keys[i];
|
|
if (!(key in current)) {
|
|
current[key] = {} as Record<string, any>;
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
current = current[key];
|
|
}
|
|
const lastKey = keys[keys.length - 1];
|
|
if (lastKey in current) {
|
|
current[lastKey] = redactedValue;
|
|
}
|
|
return obj;
|
|
}
|
|
export async function generateReport(settings: ObsidianLiveSyncSettings, core: LiveSyncBaseCore) {
|
|
let responseConfig: Record<string, any> = {};
|
|
const REDACTED = "𝑅𝐸𝐷𝐴𝐶𝑇𝐸𝐷";
|
|
if (settings.remoteType == REMOTE_COUCHDB) {
|
|
try {
|
|
const credential = generateCredentialObject(settings);
|
|
const customHeaders = parseHeaderValues(settings.couchDB_CustomHeaders);
|
|
const r = await requestToCouchDBWithCredentials(
|
|
settings.couchDB_URI,
|
|
credential,
|
|
window.origin,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
customHeaders
|
|
);
|
|
responseConfig = r.json as Record<string, any>;
|
|
redactObject(responseConfig, "couch_httpd_auth.secret");
|
|
redactObject(responseConfig, "couch_httpd_auth.authentication_db");
|
|
redactObject(responseConfig, "couch_httpd_auth.authentication_redirect");
|
|
redactObject(responseConfig, "couchdb.uuid");
|
|
redactObject(responseConfig, "admins");
|
|
redactObject(responseConfig, "users");
|
|
redactObject(responseConfig, "chttpd_auth.secret");
|
|
delete responseConfig["jwt_keys"];
|
|
} catch (ex) {
|
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
responseConfig = {
|
|
error: "Requesting information from the remote CouchDB has failed. If you are using IBM Cloudant, this is normal behaviour.",
|
|
};
|
|
}
|
|
} else if (settings.remoteType == REMOTE_MINIO) {
|
|
responseConfig = { error: "Object Storage Synchronisation" };
|
|
//
|
|
}
|
|
const defaultKeys = Object.keys(DEFAULT_SETTINGS) as (keyof ObsidianLiveSyncSettings)[];
|
|
const pluginConfig = JSON.parse(JSON.stringify(settings)) as ObsidianLiveSyncSettings;
|
|
const pluginKeys = Object.keys(pluginConfig);
|
|
for (const key of pluginKeys) {
|
|
if (defaultKeys.includes(key as keyof ObsidianLiveSyncSettings)) continue;
|
|
delete pluginConfig[key as keyof ObsidianLiveSyncSettings];
|
|
}
|
|
|
|
pluginConfig.couchDB_DBNAME = REDACTED;
|
|
pluginConfig.couchDB_PASSWORD = REDACTED;
|
|
const scheme = pluginConfig.couchDB_URI.startsWith("http:")
|
|
? "(HTTP)"
|
|
: pluginConfig.couchDB_URI.startsWith("https:")
|
|
? "(HTTPS)"
|
|
: "";
|
|
pluginConfig.couchDB_URI = isCloudantURI(pluginConfig.couchDB_URI) ? "cloudant" : `self-hosted${scheme}`;
|
|
pluginConfig.couchDB_USER = REDACTED;
|
|
pluginConfig.passphrase = REDACTED;
|
|
pluginConfig.encryptedPassphrase = REDACTED;
|
|
pluginConfig.encryptedCouchDBConnection = REDACTED;
|
|
pluginConfig.accessKey = REDACTED;
|
|
pluginConfig.secretKey = REDACTED;
|
|
const redact = (source: string) => `${REDACTED}(${source.length} letters)`;
|
|
const toSchemeOnly = (uri: string) => {
|
|
try {
|
|
return `${new URL(uri).protocol}//`;
|
|
} catch {
|
|
const matched = uri.match(/^[A-Za-z][A-Za-z0-9+.-]*:\/\//);
|
|
return matched?.[0] ?? REDACTED;
|
|
}
|
|
};
|
|
pluginConfig.remoteConfigurations = Object.fromEntries(
|
|
Object.entries(pluginConfig.remoteConfigurations || {}).map(([id, config]) => [
|
|
id,
|
|
{
|
|
...config,
|
|
uri: toSchemeOnly(config.uri),
|
|
},
|
|
])
|
|
);
|
|
pluginConfig.region = redact(pluginConfig.region);
|
|
pluginConfig.bucket = redact(pluginConfig.bucket);
|
|
pluginConfig.pluginSyncExtendedSetting = {};
|
|
pluginConfig.P2P_AppID = redact(pluginConfig.P2P_AppID);
|
|
pluginConfig.P2P_passphrase = redact(pluginConfig.P2P_passphrase);
|
|
pluginConfig.P2P_roomID = redact(pluginConfig.P2P_roomID);
|
|
pluginConfig.P2P_relays = redact(pluginConfig.P2P_relays);
|
|
pluginConfig.jwtKey = redact(pluginConfig.jwtKey);
|
|
pluginConfig.jwtSub = redact(pluginConfig.jwtSub);
|
|
pluginConfig.jwtKid = redact(pluginConfig.jwtKid);
|
|
pluginConfig.bucketCustomHeaders = redact(pluginConfig.bucketCustomHeaders);
|
|
pluginConfig.couchDB_CustomHeaders = redact(pluginConfig.couchDB_CustomHeaders);
|
|
pluginConfig.P2P_turnCredential = redact(pluginConfig.P2P_turnCredential);
|
|
pluginConfig.P2P_turnUsername = redact(pluginConfig.P2P_turnUsername);
|
|
pluginConfig.P2P_turnServers = `(${pluginConfig.P2P_turnServers.split(",").length} servers configured)`;
|
|
const endpoint = pluginConfig.endpoint;
|
|
if (endpoint == "") {
|
|
pluginConfig.endpoint = "Not configured or AWS";
|
|
} else {
|
|
const endpointScheme = pluginConfig.endpoint.startsWith("http:")
|
|
? "(HTTP)"
|
|
: pluginConfig.endpoint.startsWith("https:")
|
|
? "(HTTPS)"
|
|
: "";
|
|
pluginConfig.endpoint = `${endpoint.indexOf(".r2.cloudflarestorage.") !== -1 ? "R2" : "self-hosted?"}(${endpointScheme})`;
|
|
}
|
|
const obsidianInfo = {
|
|
navigator: compatGlobal.navigator.userAgent,
|
|
fileSystem: core.services.vault.isStorageInsensitive() ? "insensitive" : "sensitive",
|
|
};
|
|
const result = {
|
|
obsidianInfo,
|
|
responseConfig,
|
|
pluginConfig,
|
|
manifestVersion,
|
|
packageVersion,
|
|
};
|
|
return result;
|
|
}
|