mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
fix: password placeholder (#53)
This commit is contained in:
@@ -142,10 +142,7 @@ func (s *Service) Update(ctx context.Context, id string, req UpdateRequest) (Get
|
||||
baseURL = *req.BaseURL
|
||||
}
|
||||
|
||||
apiKey := existing.ApiKey
|
||||
if req.APIKey != nil {
|
||||
apiKey = *req.APIKey
|
||||
}
|
||||
apiKey := resolveUpdatedAPIKey(existing.ApiKey, req.APIKey)
|
||||
|
||||
metadata := existing.Metadata
|
||||
if req.Metadata != nil {
|
||||
@@ -253,3 +250,15 @@ func maskAPIKey(apiKey string) string {
|
||||
}
|
||||
return apiKey[:8] + strings.Repeat("*", len(apiKey)-8)
|
||||
}
|
||||
|
||||
// resolveUpdatedAPIKey keeps the original key when the request value matches the masked version.
|
||||
// This prevents masked placeholder values from overwriting the real stored credential.
|
||||
func resolveUpdatedAPIKey(existing string, updated *string) string {
|
||||
if updated == nil {
|
||||
return existing
|
||||
}
|
||||
if *updated == maskAPIKey(existing) {
|
||||
return existing
|
||||
}
|
||||
return *updated
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package providers
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestResolveUpdatedAPIKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
existing := "sk-1234567890abcdef"
|
||||
masked := maskAPIKey(existing)
|
||||
|
||||
t.Run("nil update keeps existing", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := resolveUpdatedAPIKey(existing, nil); got != existing {
|
||||
t.Fatalf("expected existing key, got %q", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("masked update keeps existing", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := resolveUpdatedAPIKey(existing, &masked); got != existing {
|
||||
t.Fatalf("expected existing key, got %q", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("new key replaces existing", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
next := "sk-new-secret"
|
||||
if got := resolveUpdatedAPIKey(existing, &next); got != next {
|
||||
t.Fatalf("expected new key, got %q", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty update clears key", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
empty := ""
|
||||
if got := resolveUpdatedAPIKey(existing, &empty); got != empty {
|
||||
t.Fatalf("expected empty key, got %q", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -32,8 +32,8 @@
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
:placeholder="$t('provider.apiKeyPlaceholder')"
|
||||
type="password"
|
||||
:placeholder="props.provider?.api_key || $t('provider.apiKeyPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -109,7 +109,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: typeof form.values]
|
||||
submit: [values: Record<string, unknown>]
|
||||
delete: []
|
||||
}>()
|
||||
|
||||
@@ -117,7 +117,7 @@ const providerSchema = toTypedSchema(z.object({
|
||||
name: z.string().min(1),
|
||||
base_url: z.string().min(1),
|
||||
client_type: z.string().min(1),
|
||||
api_key: z.string().min(1),
|
||||
api_key: z.string().optional(),
|
||||
metadata: z.object({
|
||||
additionalProp1: z.object({}),
|
||||
}),
|
||||
@@ -133,23 +133,40 @@ watch(() => props.provider, (newVal) => {
|
||||
name: newVal.name,
|
||||
base_url: newVal.base_url,
|
||||
client_type: newVal.client_type,
|
||||
api_key: newVal.api_key,
|
||||
// Keep key input empty by default so masked placeholders are never submitted back.
|
||||
api_key: '',
|
||||
})
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const hasChanges = computed(() => {
|
||||
const raw = props.provider
|
||||
return JSON.stringify(form.values) !== JSON.stringify({
|
||||
const baseChanged = JSON.stringify({
|
||||
name: form.values.name,
|
||||
base_url: form.values.base_url,
|
||||
client_type: form.values.client_type,
|
||||
metadata: form.values.metadata,
|
||||
}) !== JSON.stringify({
|
||||
name: raw?.name,
|
||||
base_url: raw?.base_url,
|
||||
client_type: raw?.client_type,
|
||||
api_key: raw?.api_key,
|
||||
metadata: { additionalProp1: {} },
|
||||
})
|
||||
|
||||
const apiKeyChanged = Boolean(form.values.api_key && form.values.api_key.trim() !== '')
|
||||
return baseChanged || apiKeyChanged
|
||||
})
|
||||
|
||||
const editProvider = form.handleSubmit(async (value) => {
|
||||
emit('submit', value)
|
||||
const payload: Record<string, unknown> = {
|
||||
name: value.name,
|
||||
base_url: value.base_url,
|
||||
client_type: value.client_type,
|
||||
metadata: value.metadata,
|
||||
}
|
||||
if (value.api_key && value.api_key.trim() !== '') {
|
||||
payload.api_key = value.api_key
|
||||
}
|
||||
emit('submit', payload)
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user