feat: add SSH commit signing to git identities
Configure commit signing per Git identity Apply SSH signing settings automatically Support signing in web and VS Code
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { toast } from '@/components/ui';
|
||||
import {
|
||||
@@ -66,6 +67,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
const [userEmail, setUserEmail] = React.useState('');
|
||||
const [authType, setAuthType] = React.useState<GitIdentityAuthType>('ssh');
|
||||
const [sshKey, setSshKey] = React.useState('');
|
||||
const [signCommits, setSignCommits] = React.useState(false);
|
||||
const [signingKey, setSigningKey] = React.useState('');
|
||||
const [host, setHost] = React.useState('');
|
||||
const [color, setColor] = React.useState('keyword');
|
||||
const [icon, setIcon] = React.useState('branch');
|
||||
@@ -83,6 +86,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
setUserEmail('');
|
||||
setAuthType('token');
|
||||
setSshKey('');
|
||||
setSignCommits(false);
|
||||
setSigningKey('');
|
||||
setHost(importData.host);
|
||||
setColor('string');
|
||||
setIcon('code');
|
||||
@@ -92,6 +97,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
setUserEmail('');
|
||||
setAuthType('ssh');
|
||||
setSshKey('');
|
||||
setSignCommits(false);
|
||||
setSigningKey('');
|
||||
setHost('');
|
||||
setColor('keyword');
|
||||
setIcon('branch');
|
||||
@@ -101,6 +108,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
setUserEmail(selectedProfile.userEmail);
|
||||
setAuthType(selectedProfile.authType || 'ssh');
|
||||
setSshKey(selectedProfile.sshKey || '');
|
||||
setSignCommits(selectedProfile.signCommits === true);
|
||||
setSigningKey(selectedProfile.signingKey || '');
|
||||
setHost(selectedProfile.host || '');
|
||||
setColor(selectedProfile.color || 'keyword');
|
||||
setIcon(selectedProfile.icon || 'branch');
|
||||
@@ -112,6 +121,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
setUserEmail(global.userEmail);
|
||||
setAuthType(global.authType || 'ssh');
|
||||
setSshKey(global.sshKey || '');
|
||||
setSignCommits(false);
|
||||
setSigningKey('');
|
||||
setHost(global.host || '');
|
||||
setColor(global.color || 'keyword');
|
||||
setIcon(global.icon || 'branch');
|
||||
@@ -128,6 +139,10 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
toast.error(t('settings.gitIdentities.editor.toast.hostRequiredForToken'));
|
||||
return;
|
||||
}
|
||||
if (signCommits && !signingKey.trim()) {
|
||||
toast.error(t('settings.gitIdentities.editor.toast.signingKeyRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
try {
|
||||
@@ -137,6 +152,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
userEmail: userEmail.trim(),
|
||||
authType,
|
||||
sshKey: authType === 'ssh' ? (sshKey.trim() || null) : null,
|
||||
signCommits,
|
||||
signingKey: signingKey.trim() || null,
|
||||
host: authType === 'token' ? (host.trim() || null) : null,
|
||||
color,
|
||||
icon,
|
||||
@@ -382,6 +399,39 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="border-t border-border/40 pt-3 space-y-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<Checkbox
|
||||
checked={signCommits}
|
||||
onChange={setSignCommits}
|
||||
ariaLabel={t('settings.gitIdentities.editor.field.signCommits')}
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<div className="typography-ui-label text-foreground">
|
||||
{t('settings.gitIdentities.editor.field.signCommits')}
|
||||
</div>
|
||||
<div className="typography-micro text-muted-foreground/70">
|
||||
{t('settings.gitIdentities.editor.section.commitSigning')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">
|
||||
{t('settings.gitIdentities.editor.field.signingKey')}
|
||||
</label>
|
||||
</div>
|
||||
<Input
|
||||
value={signingKey}
|
||||
onChange={(e) => setSigningKey(e.target.value)}
|
||||
placeholder={t('settings.gitIdentities.editor.field.signingKeyPlaceholder')}
|
||||
disabled={!signCommits}
|
||||
className="h-8 font-mono text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{authType === 'token' && (
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
|
||||
@@ -296,6 +296,8 @@ export interface GitIdentityProfile {
|
||||
userEmail: string;
|
||||
authType?: GitIdentityAuthType;
|
||||
sshKey?: string | null;
|
||||
signCommits?: boolean;
|
||||
signingKey?: string | null;
|
||||
host?: string | null;
|
||||
color?: string | null;
|
||||
icon?: string | null;
|
||||
|
||||
@@ -533,6 +533,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': 'System-wide Git identity (read-only)',
|
||||
'settings.gitIdentities.editor.description.newProfile': 'Create a new Git identity profile',
|
||||
'settings.gitIdentities.editor.description.editProfile': 'Edit identity profile settings',
|
||||
'settings.gitIdentities.editor.section.commitSigning': 'Commit signing',
|
||||
'settings.gitIdentities.editor.field.profileName': 'Profile Name',
|
||||
'settings.gitIdentities.editor.field.profileNamePlaceholder': 'Work Profile, Personal, etc.',
|
||||
'settings.gitIdentities.editor.field.color': 'Color',
|
||||
@@ -548,6 +549,9 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'SSH Key Path',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': 'Optional path to private key. e.g. ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': 'Sign commits with this identity',
|
||||
'settings.gitIdentities.editor.field.signingKey': 'Signing key',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.host': 'Host',
|
||||
'settings.gitIdentities.editor.field.hostTooltip': 'Token will be read from ~/.git-credentials for this host.',
|
||||
'settings.gitIdentities.editor.field.hostPlaceholder': 'github.com',
|
||||
@@ -556,6 +560,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.actions.save': 'Save',
|
||||
'settings.gitIdentities.editor.toast.userNameEmailRequired': 'User name and email are required',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': 'Host is required for token-based authentication',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': 'Signing key is required when commit signing is enabled',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': 'Profile created',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': 'Profile updated',
|
||||
'settings.gitIdentities.editor.toast.createProfileFailed': 'Failed to create profile',
|
||||
|
||||
@@ -500,6 +500,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.description.globalReadOnly": "Identidad Git global (solo lectura)",
|
||||
"settings.gitIdentities.editor.description.newProfile": "Crear una nueva identidad Git",
|
||||
"settings.gitIdentities.editor.description.editProfile": "Editar la configuración de la identidad",
|
||||
"settings.gitIdentities.editor.section.commitSigning": "Firma de commits",
|
||||
"settings.gitIdentities.editor.field.profileName": "Nombre de la identidad",
|
||||
"settings.gitIdentities.editor.field.profileNamePlaceholder": "Identidad de trabajo, personal, etc.",
|
||||
"settings.gitIdentities.editor.field.color": "Color",
|
||||
@@ -515,6 +516,9 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.field.sshKeyPath": "Ruta de la clave SSH",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathTooltip": "Ruta opcional a la clave privada. Ejemplo: ~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathPlaceholder": "~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.signCommits": "Firmar commits con esta identidad",
|
||||
"settings.gitIdentities.editor.field.signingKey": "Clave de firma",
|
||||
"settings.gitIdentities.editor.field.signingKeyPlaceholder": "~/.ssh/id_ed25519.pub",
|
||||
"settings.gitIdentities.editor.field.host": "Servidor",
|
||||
"settings.gitIdentities.editor.field.hostTooltip": "El token se leerá de ~/.git-credentials para este servidor.",
|
||||
"settings.gitIdentities.editor.field.hostPlaceholder": "github.com",
|
||||
@@ -523,6 +527,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.actions.save": "Guardar",
|
||||
"settings.gitIdentities.editor.toast.userNameEmailRequired": "Se requieren nombre de usuario y dirección de correo electrónico",
|
||||
"settings.gitIdentities.editor.toast.hostRequiredForToken": "Se requiere un servidor para autenticación basada en token",
|
||||
"settings.gitIdentities.editor.toast.signingKeyRequired": "Se requiere una clave de firma cuando la firma de commits está activada",
|
||||
"settings.gitIdentities.editor.toast.profileCreated": "Identidad creada",
|
||||
"settings.gitIdentities.editor.toast.profileUpdated": "Identidad actualizada",
|
||||
"settings.gitIdentities.editor.toast.createProfileFailed": "No se pudo crear la identidad",
|
||||
|
||||
@@ -489,6 +489,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': 'Identité Git à l\'échelle du système (lecture seule)',
|
||||
'settings.gitIdentities.editor.description.newProfile': 'Créer un nouveau profil d\'identité Git',
|
||||
'settings.gitIdentities.editor.description.editProfile': 'Modifier les paramètres du profil d\'identité',
|
||||
'settings.gitIdentities.editor.section.commitSigning': 'Signature des commits',
|
||||
'settings.gitIdentities.editor.field.profileName': 'Nom du profil',
|
||||
'settings.gitIdentities.editor.field.profileNamePlaceholder': 'Profil professionnel, personnel, etc.',
|
||||
'settings.gitIdentities.editor.field.color': 'Couleur',
|
||||
@@ -504,6 +505,9 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'Chemin clé SSH',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': 'Chemin facultatif vers la clé privée. e.g. ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': 'Signer les commits avec cette identité',
|
||||
'settings.gitIdentities.editor.field.signingKey': 'Clé de signature',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.host': 'Hôte',
|
||||
'settings.gitIdentities.editor.field.hostTooltip': 'Le jeton sera lu à partir de ~/.git-credentials pour cet hôte.',
|
||||
'settings.gitIdentities.editor.field.hostPlaceholder': 'github.com',
|
||||
@@ -512,6 +516,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.actions.save': 'Sauvegarder',
|
||||
'settings.gitIdentities.editor.toast.userNameEmailRequired': 'Le nom d\'utilisateur et l\'e-mail sont requis',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': 'L\'hôte est requis pour l\'authentification basée sur un jeton',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': 'Une clé de signature est requise lorsque la signature des commits est activée',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': 'Profil créé',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': 'Profil mis à jour',
|
||||
'settings.gitIdentities.editor.toast.createProfileFailed': 'Échec de la création du profil',
|
||||
|
||||
@@ -500,6 +500,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': '시스템 전체 Git 자격 증명(읽기 전용)',
|
||||
'settings.gitIdentities.editor.description.newProfile': '새 Git 자격 증명 프로필을 생성하세요',
|
||||
'settings.gitIdentities.editor.description.editProfile': 'Git 자격 증명 프로필 설정을 편집하세요',
|
||||
'settings.gitIdentities.editor.section.commitSigning': '커밋 서명',
|
||||
'settings.gitIdentities.editor.field.profileName': '프로필 이름',
|
||||
'settings.gitIdentities.editor.field.profileNamePlaceholder': 'Work Profile, Personal 등',
|
||||
'settings.gitIdentities.editor.field.color': '색상',
|
||||
@@ -515,6 +516,9 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'SSH 키 경로',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': '개인 키의 선택적 경로입니다. 예: ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': '이 ID로 커밋 서명',
|
||||
'settings.gitIdentities.editor.field.signingKey': '서명 키',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.host': 'Host',
|
||||
'settings.gitIdentities.editor.field.hostTooltip': '이 host의 토큰은 ~/.git-credentials에서 읽습니다.',
|
||||
'settings.gitIdentities.editor.field.hostPlaceholder': 'github.com',
|
||||
@@ -523,6 +527,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.actions.save': '저장',
|
||||
'settings.gitIdentities.editor.toast.userNameEmailRequired': '사용자 이름과 이메일은 필수입니다',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': '토큰 기반 인증에는 host가 필요합니다',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': '커밋 서명이 활성화되면 서명 키가 필요합니다',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': '프로필이 생성되었습니다',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': '프로필이 업데이트되었습니다',
|
||||
'settings.gitIdentities.editor.toast.createProfileFailed': '프로필을 생성하지 못했습니다',
|
||||
|
||||
@@ -178,6 +178,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.description.editProfile': 'Edytuj ustawienia profilu tożsamości',
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': 'Globalna tożsamość Git (tylko do odczytu)',
|
||||
'settings.gitIdentities.editor.description.newProfile': 'Utwórz nowy profil tożsamości Git',
|
||||
'settings.gitIdentities.editor.section.commitSigning': 'Podpisywanie commitów',
|
||||
'settings.gitIdentities.editor.field.authMethod': 'Metoda uwierzytelniania',
|
||||
'settings.gitIdentities.editor.field.authToken': 'Token',
|
||||
'settings.gitIdentities.editor.field.color': 'Kolor',
|
||||
@@ -193,6 +194,9 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'Ścieżka do klucza SSH',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': 'Opcjonalna ścieżka do klucza prywatnego, np. ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': 'Podpisuj commity tą tożsamością',
|
||||
'settings.gitIdentities.editor.field.signingKey': 'Klucz podpisu',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.userName': 'Nazwa użytkownika',
|
||||
'settings.gitIdentities.editor.field.userNamePlaceholder': 'Jan Kowalski',
|
||||
'settings.gitIdentities.editor.field.userNameTooltip': 'Nazwa, która pojawi się w wiadomościach commitów Git.',
|
||||
@@ -204,6 +208,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.toast.deleteProfileFailed': 'Nie udało się usunąć profilu',
|
||||
'settings.gitIdentities.editor.toast.deleteUnexpectedError': 'Wystąpił błąd podczas usuwania',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': 'Host jest wymagany dla uwierzytelniania opartego na tokenie',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': 'Klucz podpisu jest wymagany, gdy włączone jest podpisywanie commitów',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': 'Profil utworzony',
|
||||
'settings.gitIdentities.editor.toast.profileDeleted': 'Profil usunięty',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': 'Profil zaktualizowany',
|
||||
|
||||
@@ -500,6 +500,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.description.globalReadOnly": "Identidade Git global (somente leitura)",
|
||||
"settings.gitIdentities.editor.description.newProfile": "Criar uma nova identidade Git",
|
||||
"settings.gitIdentities.editor.description.editProfile": "Editar as configurações da identidade",
|
||||
"settings.gitIdentities.editor.section.commitSigning": "Assinatura de commits",
|
||||
"settings.gitIdentities.editor.field.profileName": "Nome da identidade",
|
||||
"settings.gitIdentities.editor.field.profileNamePlaceholder": "Identidade de trabalho, pessoal, etc.",
|
||||
"settings.gitIdentities.editor.field.color": "Cor",
|
||||
@@ -515,6 +516,9 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.field.sshKeyPath": "Caminho da chave SSH",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathTooltip": "Caminho opcional para a chave privada. Exemplo: ~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathPlaceholder": "~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.signCommits": "Assinar commits com esta identidade",
|
||||
"settings.gitIdentities.editor.field.signingKey": "Chave de assinatura",
|
||||
"settings.gitIdentities.editor.field.signingKeyPlaceholder": "~/.ssh/id_ed25519.pub",
|
||||
"settings.gitIdentities.editor.field.host": "Servidor",
|
||||
"settings.gitIdentities.editor.field.hostTooltip": "O token será lido de ~/.git-credentials para este servidor.",
|
||||
"settings.gitIdentities.editor.field.hostPlaceholder": "github.com",
|
||||
@@ -523,6 +527,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.actions.save": "Salvar",
|
||||
"settings.gitIdentities.editor.toast.userNameEmailRequired": "Nome de usuário e endereço de e-mail são obrigatórios",
|
||||
"settings.gitIdentities.editor.toast.hostRequiredForToken": "É necessário um servidor para autenticação baseada em token",
|
||||
"settings.gitIdentities.editor.toast.signingKeyRequired": "É necessária uma chave de assinatura quando a assinatura de commits está ativada",
|
||||
"settings.gitIdentities.editor.toast.profileCreated": "Identidade criada",
|
||||
"settings.gitIdentities.editor.toast.profileUpdated": "Identidade atualizada",
|
||||
"settings.gitIdentities.editor.toast.createProfileFailed": "Não foi possível criar a identidade",
|
||||
|
||||
@@ -500,6 +500,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.description.globalReadOnly": "Глобальна Git-ідентичність (лише для читання)",
|
||||
"settings.gitIdentities.editor.description.newProfile": "Створити новий профіль Git-ідентичності",
|
||||
"settings.gitIdentities.editor.description.editProfile": "Редагувати налаштування профілю ідентичності",
|
||||
"settings.gitIdentities.editor.section.commitSigning": "Підписування комітів",
|
||||
"settings.gitIdentities.editor.field.profileName": "Ім'я профілю",
|
||||
"settings.gitIdentities.editor.field.profileNamePlaceholder": "Робочий профіль, особистий тощо.",
|
||||
"settings.gitIdentities.editor.field.color": "Колір",
|
||||
@@ -515,6 +516,9 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.field.sshKeyPath": "Шлях до SSH-ключа",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathTooltip": "Додатковий шлях до закритого ключа. напр. ~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.sshKeyPathPlaceholder": "~/.ssh/id_ed25519",
|
||||
"settings.gitIdentities.editor.field.signCommits": "Підписувати коміти цією ідентичністю",
|
||||
"settings.gitIdentities.editor.field.signingKey": "Ключ підпису",
|
||||
"settings.gitIdentities.editor.field.signingKeyPlaceholder": "~/.ssh/id_ed25519.pub",
|
||||
"settings.gitIdentities.editor.field.host": "Хост",
|
||||
"settings.gitIdentities.editor.field.hostTooltip": "Токен буде зчитано з облікових даних ~/.git для цього хосту.",
|
||||
"settings.gitIdentities.editor.field.hostPlaceholder": "github.com",
|
||||
@@ -523,6 +527,7 @@ export const settingsDict = {
|
||||
"settings.gitIdentities.editor.actions.save": "Зберегти",
|
||||
"settings.gitIdentities.editor.toast.userNameEmailRequired": "Необхідно вказати ім’я користувача та електронну адресу",
|
||||
"settings.gitIdentities.editor.toast.hostRequiredForToken": "Для автентифікації на основі токенів потрібен хост",
|
||||
"settings.gitIdentities.editor.toast.signingKeyRequired": "Потрібен ключ підпису, коли ввімкнено підписування комітів",
|
||||
"settings.gitIdentities.editor.toast.profileCreated": "Профіль створено",
|
||||
"settings.gitIdentities.editor.toast.profileUpdated": "Профіль оновлено",
|
||||
"settings.gitIdentities.editor.toast.createProfileFailed": "Не вдалося створити профіль",
|
||||
|
||||
@@ -500,6 +500,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': '系统范围 Git 身份(只读)',
|
||||
'settings.gitIdentities.editor.description.newProfile': '创建新的 Git 身份配置',
|
||||
'settings.gitIdentities.editor.description.editProfile': '编辑身份配置设置',
|
||||
'settings.gitIdentities.editor.section.commitSigning': '提交签名',
|
||||
'settings.gitIdentities.editor.field.profileName': '身份名称',
|
||||
'settings.gitIdentities.editor.field.profileNamePlaceholder': '工作身份、个人身份等',
|
||||
'settings.gitIdentities.editor.field.color': '颜色',
|
||||
@@ -515,6 +516,9 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'SSH 密钥路径',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': '可选私钥路径,例如 ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': '使用此身份签名提交',
|
||||
'settings.gitIdentities.editor.field.signingKey': '签名密钥',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.host': 'Host',
|
||||
'settings.gitIdentities.editor.field.hostTooltip': '该 host 的 token 将从 ~/.git-credentials 读取。',
|
||||
'settings.gitIdentities.editor.field.hostPlaceholder': 'github.com',
|
||||
@@ -523,6 +527,7 @@ export const settingsDict = {
|
||||
'settings.gitIdentities.editor.actions.save': '保存',
|
||||
'settings.gitIdentities.editor.toast.userNameEmailRequired': '用户名和邮箱为必填项',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': '基于 token 认证时 Host 为必填项',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': '启用提交签名时需要签名密钥',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': '身份已创建',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': '身份已更新',
|
||||
'settings.gitIdentities.editor.toast.createProfileFailed': '创建身份失败',
|
||||
|
||||
@@ -497,6 +497,7 @@
|
||||
'settings.gitIdentities.editor.description.globalReadOnly': '系統範圍 Git 身分(唯讀)',
|
||||
'settings.gitIdentities.editor.description.newProfile': '建立新的 Git 身分設定',
|
||||
'settings.gitIdentities.editor.description.editProfile': '編輯身分設定',
|
||||
'settings.gitIdentities.editor.section.commitSigning': '提交簽章',
|
||||
'settings.gitIdentities.editor.field.profileName': '身分名稱',
|
||||
'settings.gitIdentities.editor.field.profileNamePlaceholder': '工作身分、個人身分等',
|
||||
'settings.gitIdentities.editor.field.color': '顏色',
|
||||
@@ -512,6 +513,9 @@
|
||||
'settings.gitIdentities.editor.field.sshKeyPath': 'SSH 金鑰路徑',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathTooltip': '可選私鑰路徑,例如 ~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.sshKeyPathPlaceholder': '~/.ssh/id_ed25519',
|
||||
'settings.gitIdentities.editor.field.signCommits': '使用此身分簽署提交',
|
||||
'settings.gitIdentities.editor.field.signingKey': '簽章金鑰',
|
||||
'settings.gitIdentities.editor.field.signingKeyPlaceholder': '~/.ssh/id_ed25519.pub',
|
||||
'settings.gitIdentities.editor.field.host': 'Host',
|
||||
'settings.gitIdentities.editor.field.hostTooltip': '該 host 的 token 將從 ~/.git-credentials 讀取。',
|
||||
'settings.gitIdentities.editor.field.hostPlaceholder': 'github.com',
|
||||
@@ -520,6 +524,7 @@
|
||||
'settings.gitIdentities.editor.actions.save': '儲存',
|
||||
'settings.gitIdentities.editor.toast.userNameEmailRequired': '使用者名稱和電子郵件為必填項',
|
||||
'settings.gitIdentities.editor.toast.hostRequiredForToken': '基於 token 驗證時 Host 為必填項',
|
||||
'settings.gitIdentities.editor.toast.signingKeyRequired': '啟用提交簽章時需要簽章金鑰',
|
||||
'settings.gitIdentities.editor.toast.profileCreated': '身分已建立',
|
||||
'settings.gitIdentities.editor.toast.profileUpdated': '身分已更新',
|
||||
'settings.gitIdentities.editor.toast.createProfileFailed': '建立身分失敗',
|
||||
|
||||
@@ -316,7 +316,7 @@ export const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
|
||||
page: 'git',
|
||||
titleKey: 'settings.gitIdentities.page.section.title',
|
||||
descriptionKey: 'settings.gitIdentities.page.empty.description',
|
||||
keywords: ['identity', 'profile', 'author', 'email', 'credentials'],
|
||||
keywords: ['identity', 'profile', 'author', 'email', 'credentials', 'signing', 'commit signing', 'ssh signing', 'gpg'],
|
||||
},
|
||||
{
|
||||
id: 'git.changes-view',
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface GitIdentityProfile {
|
||||
userEmail: string;
|
||||
authType?: GitIdentityAuthType;
|
||||
sshKey?: string | null;
|
||||
signCommits?: boolean;
|
||||
signingKey?: string | null;
|
||||
host?: string | null;
|
||||
color?: string | null;
|
||||
icon?: string | null;
|
||||
|
||||
@@ -531,12 +531,14 @@ export async function handleStandardGitBridgeMessage(message: BridgeMessageInput
|
||||
}
|
||||
|
||||
case 'api:git/identity': {
|
||||
const { directory, method, userName, userEmail, sshKey } = (payload || {}) as {
|
||||
const { directory, method, userName, userEmail, sshKey, signCommits, signingKey } = (payload || {}) as {
|
||||
directory?: string;
|
||||
method?: string;
|
||||
userName?: string;
|
||||
userEmail?: string;
|
||||
sshKey?: string | null;
|
||||
signCommits?: boolean;
|
||||
signingKey?: string | null;
|
||||
};
|
||||
const dirError = requireDirectory(id, type, directory);
|
||||
if (dirError) return dirError;
|
||||
@@ -552,7 +554,14 @@ export async function handleStandardGitBridgeMessage(message: BridgeMessageInput
|
||||
if (!userName || !userEmail) {
|
||||
return { id, type, success: false, error: 'userName and userEmail are required' };
|
||||
}
|
||||
const result = await gitService.setGitIdentity(directory!, userName, userEmail, sshKey);
|
||||
const result = await gitService.setGitIdentity(
|
||||
directory!,
|
||||
userName,
|
||||
userEmail,
|
||||
sshKey,
|
||||
signCommits === true,
|
||||
signingKey ?? null
|
||||
);
|
||||
return { id, type, success: true, data: result };
|
||||
}
|
||||
|
||||
|
||||
@@ -3284,12 +3284,15 @@ export async function setGitIdentity(
|
||||
directory: string,
|
||||
userName: string,
|
||||
userEmail: string,
|
||||
sshKey?: string | null
|
||||
sshKey?: string | null,
|
||||
signCommits?: boolean | null,
|
||||
signingKey?: string | null
|
||||
): Promise<{ success: boolean }> {
|
||||
const repo = await getRepository(directory);
|
||||
|
||||
// Build SSH command once if needed
|
||||
const sshCommand = sshKey ? buildSshCommand(sshKey) : null;
|
||||
const shouldSignCommits = signCommits === true && typeof signingKey === 'string' && signingKey.trim().length > 0;
|
||||
|
||||
if (repo) {
|
||||
try {
|
||||
@@ -3298,6 +3301,11 @@ export async function setGitIdentity(
|
||||
if (sshCommand) {
|
||||
await repo.setConfig('core.sshCommand', sshCommand);
|
||||
}
|
||||
if (shouldSignCommits) {
|
||||
await repo.setConfig('gpg.format', 'ssh');
|
||||
await repo.setConfig('user.signingkey', signingKey.trim());
|
||||
await repo.setConfig('commit.gpgsign', 'true');
|
||||
}
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[GitService] Failed to set identity:', error);
|
||||
@@ -3310,6 +3318,11 @@ export async function setGitIdentity(
|
||||
if (sshCommand) {
|
||||
await execGit(['config', 'core.sshCommand', sshCommand], directory);
|
||||
}
|
||||
if (shouldSignCommits) {
|
||||
await execGit(['config', 'gpg.format', 'ssh'], directory);
|
||||
await execGit(['config', 'user.signingkey', signingKey.trim()], directory);
|
||||
await execGit(['config', 'commit.gpgsign', 'true'], directory);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -41,6 +41,24 @@ import type {
|
||||
ResetToCommitResponse,
|
||||
} from '@openchamber/ui/lib/api/types';
|
||||
|
||||
type GitIdentityStoreState = {
|
||||
profiles: GitIdentityProfile[];
|
||||
};
|
||||
|
||||
type GitIdentityStoreApi = {
|
||||
getState: () => GitIdentityStoreState;
|
||||
setState: (
|
||||
nextState: GitIdentityStoreState | ((state: GitIdentityStoreState) => GitIdentityStoreState),
|
||||
replace?: boolean
|
||||
) => void;
|
||||
};
|
||||
|
||||
const getGitIdentityStore = (): GitIdentityStoreApi | undefined => (
|
||||
window as Window & {
|
||||
__zustand_git_identities_store__?: GitIdentityStoreApi;
|
||||
}
|
||||
).__zustand_git_identities_store__;
|
||||
|
||||
export const createVSCodeGitAPI = (): GitAPI => ({
|
||||
checkIsGitRepository: async (directory: string): Promise<boolean> => {
|
||||
return sendBridgeMessage<boolean>('api:git/check', { directory });
|
||||
@@ -311,31 +329,69 @@ export const createVSCodeGitAPI = (): GitAPI => ({
|
||||
},
|
||||
|
||||
setGitIdentity: async (directory: string, profileId: string): Promise<{ success: boolean; profile: GitIdentityProfile }> => {
|
||||
// For VS Code, we need to resolve the profile from the store
|
||||
// This is a simplified implementation - the full implementation would need profile lookup
|
||||
const store = (window as Window & {
|
||||
__zustand_git_identities_store__?: {
|
||||
getState: () => {
|
||||
getProfileById: (id: string) => GitIdentityProfile | undefined;
|
||||
};
|
||||
};
|
||||
}).__zustand_git_identities_store__;
|
||||
const profile = store?.getState().getProfileById(profileId);
|
||||
if (!profile) {
|
||||
return {
|
||||
success: false,
|
||||
profile: { id: profileId, name: '', userName: '', userEmail: '' },
|
||||
};
|
||||
}
|
||||
|
||||
const result = await sendBridgeMessage<{ success: boolean }>('api:git/identity', {
|
||||
directory,
|
||||
method: 'POST',
|
||||
userName: profile.userName,
|
||||
userEmail: profile.userEmail,
|
||||
sshKey: profile.sshKey ?? null,
|
||||
signCommits: profile.signCommits === true,
|
||||
signingKey: profile.signingKey ?? null,
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
profile: { id: profileId, name: '', userName: '', userEmail: '' },
|
||||
success: result.success === true,
|
||||
profile,
|
||||
};
|
||||
},
|
||||
|
||||
// Git identity profile management - these are stored in extension settings
|
||||
// For simplicity, return empty arrays/objects as these are managed through the settings UI
|
||||
// Git identity profile management is backed by the webview store in VS Code.
|
||||
getGitIdentities: async (): Promise<GitIdentityProfile[]> => {
|
||||
return [];
|
||||
return getGitIdentityStore()?.getState().profiles ?? [];
|
||||
},
|
||||
|
||||
createGitIdentity: async (profile: GitIdentityProfile): Promise<GitIdentityProfile> => {
|
||||
const store = getGitIdentityStore();
|
||||
if (store) {
|
||||
store.setState((state) => ({
|
||||
profiles: [...state.profiles.filter((existing) => existing.id !== profile.id), profile],
|
||||
}));
|
||||
}
|
||||
return profile;
|
||||
},
|
||||
|
||||
updateGitIdentity: async (id: string, profile: GitIdentityProfile): Promise<GitIdentityProfile> => {
|
||||
void id; // Unused for now
|
||||
const store = getGitIdentityStore();
|
||||
if (store) {
|
||||
store.setState((state) => ({
|
||||
profiles: state.profiles.map((existing) => (existing.id === id ? { ...existing, ...profile, id } : existing)),
|
||||
}));
|
||||
}
|
||||
return profile;
|
||||
},
|
||||
|
||||
deleteGitIdentity: async (id: string): Promise<void> => {
|
||||
void id; // Unused for now
|
||||
const store = getGitIdentityStore();
|
||||
if (store) {
|
||||
store.setState((state) => ({
|
||||
profiles: state.profiles.filter((existing) => existing.id !== id),
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
getRemotes: async (directory: string): Promise<GitRemote[]> => {
|
||||
|
||||
@@ -68,6 +68,8 @@ export function createProfile(profileData) {
|
||||
userEmail: profileData.userEmail,
|
||||
authType: profileData.authType || 'ssh',
|
||||
sshKey: profileData.sshKey || null,
|
||||
signCommits: profileData.signCommits,
|
||||
signingKey: profileData.signingKey || null,
|
||||
host: profileData.host || null,
|
||||
color: profileData.color || 'keyword',
|
||||
icon: profileData.icon || 'branch'
|
||||
|
||||
@@ -1913,6 +1913,12 @@ export async function setLocalIdentity(directory, profile) {
|
||||
await git.raw(['config', '--local', '--unset', 'core.sshCommand']).catch(() => {});
|
||||
}
|
||||
|
||||
if (profile.signCommits === true && typeof profile.signingKey === 'string' && profile.signingKey.trim()) {
|
||||
await git.addConfig('gpg.format', 'ssh', false, 'local');
|
||||
await git.addConfig('user.signingkey', profile.signingKey.trim(), false, 'local');
|
||||
await git.addConfig('commit.gpgsign', 'true', false, 'local');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Failed to set Git identity:', error);
|
||||
|
||||
Reference in New Issue
Block a user