Fix PBS certificate validation: pass PBS_FINGERPRINT, optional fingerprint for trusted CA
- Pass stored pbs_fingerprint as PBS_FINGERPRINT in login, snapshot list, and restore - Allow empty fingerprint so trusted-CA PBS works without entering one - Make fingerprint field optional in PBSCredentialsModal with updated helper text Fixes #438
This commit is contained in:
@@ -270,22 +270,21 @@ export function PBSCredentialsModal({
|
||||
htmlFor="pbs-fingerprint"
|
||||
className="text-foreground mb-1 block text-sm font-medium"
|
||||
>
|
||||
Fingerprint <span className="text-error">*</span>
|
||||
Fingerprint
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="pbs-fingerprint"
|
||||
value={pbsFingerprint}
|
||||
onChange={(e) => setPbsFingerprint(e.target.value)}
|
||||
required
|
||||
disabled={isLoading}
|
||||
className="bg-card text-foreground placeholder-muted-foreground focus:ring-ring focus:border-ring border-border w-full rounded-md border px-3 py-2 shadow-sm focus:ring-2 focus:outline-none"
|
||||
placeholder="e.g., 7b:e5:87:38:5e:16:05:d1:12:22:7f:73:d2:e2:d0:cf:8c:cb:28:e2:74:0c:78:91:1a:71:74:2e:79:20:5a:02"
|
||||
/>
|
||||
<p className="text-muted-foreground mt-1 text-xs">
|
||||
Server fingerprint for auto-acceptance. You can find this on
|
||||
your PBS dashboard by clicking the "Show Fingerprint"
|
||||
button.
|
||||
Leave empty if PBS uses a trusted CA (e.g. Let's Encrypt).
|
||||
For self-signed certificates, enter the server fingerprint from
|
||||
the PBS dashboard ("Show Fingerprint").
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -327,13 +327,16 @@ class BackupService {
|
||||
// PBS supports PBS_PASSWORD and PBS_REPOSITORY environment variables for non-interactive login
|
||||
const repository = `root@pam@${pbsIp}:${pbsDatastore}`;
|
||||
|
||||
// Escape password for shell safety (single quotes)
|
||||
// Escape password and fingerprint for shell safety (single quotes)
|
||||
const escapedPassword = credential.pbs_password.replace(/'/g, "'\\''");
|
||||
|
||||
// Use PBS_PASSWORD environment variable for non-interactive authentication
|
||||
// Auto-accept fingerprint by piping "y" to stdin
|
||||
// PBS will use PBS_PASSWORD env var if available, avoiding interactive prompt
|
||||
const fullCommand = `echo "y" | PBS_PASSWORD='${escapedPassword}' PBS_REPOSITORY='${repository}' timeout 10 proxmox-backup-client login --repository ${repository} 2>&1`;
|
||||
const fingerprint = credential.pbs_fingerprint?.trim() ?? '';
|
||||
const escapedFingerprint = fingerprint ? fingerprint.replace(/'/g, "'\\''") : '';
|
||||
const envParts = [`PBS_PASSWORD='${escapedPassword}'`, `PBS_REPOSITORY='${repository}'`];
|
||||
if (escapedFingerprint) {
|
||||
envParts.push(`PBS_FINGERPRINT='${escapedFingerprint}'`);
|
||||
}
|
||||
const envStr = envParts.join(' ');
|
||||
const fullCommand = `${envStr} timeout 10 proxmox-backup-client login --repository ${repository} 2>&1`;
|
||||
|
||||
console.log(`[BackupService] Logging into PBS: ${repository}`);
|
||||
|
||||
@@ -419,9 +422,12 @@ class BackupService {
|
||||
|
||||
// Build full repository string: root@pam@<IP>:<DATASTORE>
|
||||
const repository = `root@pam@${pbsIp}:${pbsDatastore}`;
|
||||
|
||||
const fingerprint = credential.pbs_fingerprint?.trim() ?? '';
|
||||
const escapedFingerprint = fingerprint ? fingerprint.replace(/'/g, "'\\''") : '';
|
||||
const snapshotEnvParts = escapedFingerprint ? [`PBS_FINGERPRINT='${escapedFingerprint}'`] : [];
|
||||
const snapshotEnvStr = snapshotEnvParts.length ? snapshotEnvParts.join(' ') + ' ' : '';
|
||||
// Use correct command: snapshot list ct/<CT_ID> --repository <full_repo_string>
|
||||
const command = `timeout 30 proxmox-backup-client snapshot list ct/${ctId} --repository ${repository} 2>&1 || echo "PBS_ERROR"`;
|
||||
const command = `${snapshotEnvStr}timeout 30 proxmox-backup-client snapshot list ct/${ctId} --repository ${repository} 2>&1 || echo "PBS_ERROR"`;
|
||||
let output = '';
|
||||
|
||||
console.log(`[BackupService] Discovering PBS backups for CT ${ctId} on repository ${repository}`);
|
||||
|
||||
@@ -250,9 +250,16 @@ class RestoreService {
|
||||
const targetFolder = `/var/lib/vz/dump/vzdump-lxc-${ctId}-${snapshotNameForPath}`;
|
||||
const targetTar = `${targetFolder}.tar`;
|
||||
|
||||
// Use PBS_PASSWORD env var and add timeout for long downloads
|
||||
// Use PBS_PASSWORD env var and add timeout for long downloads; PBS_FINGERPRINT when set for cert validation
|
||||
const escapedPassword = credential.pbs_password.replace(/'/g, "'\\''");
|
||||
const restoreCommand = `PBS_PASSWORD='${escapedPassword}' PBS_REPOSITORY='${repository}' timeout 300 proxmox-backup-client restore "${snapshotPath}" root.pxar "${targetFolder}" --repository '${repository}' 2>&1`;
|
||||
const fingerprint = credential.pbs_fingerprint?.trim() ?? '';
|
||||
const escapedFingerprint = fingerprint ? fingerprint.replace(/'/g, "'\\''") : '';
|
||||
const restoreEnvParts = [`PBS_PASSWORD='${escapedPassword}'`, `PBS_REPOSITORY='${repository}'`];
|
||||
if (escapedFingerprint) {
|
||||
restoreEnvParts.push(`PBS_FINGERPRINT='${escapedFingerprint}'`);
|
||||
}
|
||||
const restoreEnvStr = restoreEnvParts.join(' ');
|
||||
const restoreCommand = `${restoreEnvStr} timeout 300 proxmox-backup-client restore "${snapshotPath}" root.pxar "${targetFolder}" --repository '${repository}' 2>&1`;
|
||||
|
||||
let output = '';
|
||||
let exitCode = 0;
|
||||
|
||||
Reference in New Issue
Block a user