Add optional secret export

This commit is contained in:
shi.changliang 2026-06-05 09:48:53 +08:00
parent c50ac4bbfa
commit b4ce1005f0
3 changed files with 62 additions and 13 deletions

View file

@ -32,6 +32,8 @@ interface ConnectionConfig {
accountKey: string;
vaultKey: string;
vaultId?: string;
accessKeyId?: string;
secretAccessKey?: string;
}
const DEFAULT_SETTINGS: ObsyncSettings = {
@ -326,8 +328,8 @@ export default class ObsyncPlugin extends Plugin {
await this.saveSettings();
}
getConnectionConfig(): Record<string, string | number> {
return {
getConnectionConfig(includeSecrets = false): Record<string, string | number> {
const config: Record<string, string | number> = {
schemaVersion: 1,
endpoint: this.settings.endpoint,
bucket: this.settings.bucket,
@ -337,6 +339,13 @@ export default class ObsyncPlugin extends Plugin {
vaultKey: this.settings.vaultKey,
vaultId: this.settings.vaultId,
};
if (includeSecrets) {
config.accessKeyId = this.settings.accessKeyId;
config.secretAccessKey = this.settings.secretAccessKey;
}
return config;
}
async importConnectionConfig(configText: string): Promise<void> {
@ -349,6 +358,8 @@ export default class ObsyncPlugin extends Plugin {
rootPrefix: config.rootPrefix,
accountKey: config.accountKey,
vaultKey: config.vaultKey,
accessKeyId: config.accessKeyId || this.settings.accessKeyId,
secretAccessKey: config.secretAccessKey || this.settings.secretAccessKey,
});
}
}
@ -394,6 +405,8 @@ function parseConnectionConfig(configText: string): ConnectionConfig {
accountKey: readOptionalString(parsed, "accountKey", "default"),
vaultKey: readRequiredString(parsed, "vaultKey"),
vaultId: readOptionalString(parsed, "vaultId", ""),
accessKeyId: readOptionalString(parsed, "accessKeyId", ""),
secretAccessKey: readOptionalString(parsed, "secretAccessKey", ""),
};
if (config.vaultId) {
@ -535,9 +548,9 @@ class ObsyncSettingTab extends PluginSettingTab {
await navigator.clipboard.writeText(this.plugin.settings.deviceId);
new Notice("设备 ID 已复制。");
},
onCopyConnectionConfig: async () => {
await navigator.clipboard.writeText(JSON.stringify(this.plugin.getConnectionConfig(), null, 2));
new Notice("连接配置已复制。");
onCopyConnectionConfig: async (includeSecrets: boolean) => {
await navigator.clipboard.writeText(JSON.stringify(this.plugin.getConnectionConfig(includeSecrets), null, 2));
new Notice(includeSecrets ? "完整连接配置已复制。" : "连接配置已复制。");
},
onPasteConnectionConfig: async () => {
try {
@ -545,7 +558,8 @@ class ObsyncSettingTab extends PluginSettingTab {
await this.plugin.importConnectionConfig(configText);
Object.assign(settings, this.plugin.settings);
Object.assign(connectionConfig, this.plugin.getConnectionConfig());
new Notice("连接配置已导入。请继续填写 Access Key ID 和 Secret Access Key。");
const hasSecrets = Boolean(this.plugin.settings.accessKeyId && this.plugin.settings.secretAccessKey);
new Notice(hasSecrets ? "连接配置已导入。" : "连接配置已导入。请继续填写 Access Key ID 和 Secret Access Key。");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
new Notice(`导入连接配置失败:${message}`);

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { setIcon } from "obsidian";
import { ref, watchEffect } from "vue";
import { computed, ref, watchEffect } from "vue";
type ObsyncSettings = {
endpoint: string;
@ -26,13 +26,25 @@ const props = defineProps<{
const emit = defineEmits<{
update: [update: Partial<ObsyncSettings>];
copyDeviceId: [];
copyConnectionConfig: [];
copyConnectionConfig: [includeSecrets: boolean];
pasteConnectionConfig: [];
releaseDeletedContent: [];
}>();
const showSecretAccessKey = ref(false);
const includeSecrets = ref(false);
const secretAccessKeyButton = ref<HTMLButtonElement | null>(null);
const connectionConfigPreview = computed(() => {
if (!includeSecrets.value) {
return props.connectionConfig;
}
return {
...props.connectionConfig,
accessKeyId: props.settings.accessKeyId,
secretAccessKey: props.settings.secretAccessKey,
};
});
watchEffect(() => {
const button = secretAccessKeyButton.value;
@ -242,15 +254,33 @@ watchEffect(() => {
<section class="obsync-card">
<div class="obsync-row obsync-row-block">
<div class="obsync-row-copy">
<h3>连接配置</h3>
<p>复制到另一台设备导入这里不包含 Access Key Secret</p>
<div class="obsync-row-title">
<div>
<h3>连接配置</h3>
<p>
{{ includeSecrets ? "将包含 Access Key 和 Secret仅用于导入自己的设备。" : "复制到另一台设备导入。默认不包含 Access Key 和 Secret。" }}
</p>
</div>
<label class="obsync-inline-switch">
<span>包含密钥</span>
<span class="obsync-switch">
<input
type="checkbox"
:checked="includeSecrets"
@change="includeSecrets = ($event.target as HTMLInputElement).checked"
/>
<span></span>
</span>
</label>
</div>
</div>
<pre class="obsync-config-display">{{ JSON.stringify(props.connectionConfig, null, 2) }}</pre>
<pre class="obsync-config-display">{{ JSON.stringify(connectionConfigPreview, null, 2) }}</pre>
<div class="obsync-action-row">
<button type="button" class="obsync-primary" @click="emit('copyConnectionConfig')">
复制连接配置
<button type="button" class="obsync-primary" @click="emit('copyConnectionConfig', includeSecrets)">
{{ includeSecrets ? "复制完整配置" : "复制连接配置" }}
</button>
<button type="button" class="obsync-secondary" @click="emit('pasteConnectionConfig')">

View file

@ -94,6 +94,11 @@
@apply flex items-center justify-between gap-3;
}
.obsync-inline-switch {
@apply flex shrink-0 cursor-pointer items-center gap-2 text-sm font-medium;
color: var(--text-muted);
}
.obsync-link-button {
@apply shrink-0 cursor-pointer rounded px-2 py-1 text-xs font-semibold leading-4 transition;
background: transparent;