feat: complete API token export/import with version handling

Complete the API token export/import feature with proper version
handling and backward compatibility:

- Bump export format to version 4.1 to indicate API token support
- Import API tokens when loading v4.1 exports
- Handle version compatibility gracefully:
  - v4.1: Full support including API tokens
  - v4.0: Notice that tokens weren't included (backward compatible)
  - Other: Warning but best-effort import
- Initialize empty array instead of nil for cleaner JSON

This ensures API tokens are properly preserved when migrating or
restoring Pulse instances while maintaining backward compatibility
with older exports.
This commit is contained in:
rcourtman 2025-10-21 11:38:23 +00:00
parent 59cd456428
commit bd13b966d0

View file

@ -84,8 +84,8 @@ func (c *ConfigPersistence) ExportConfig(passphrase string) (string, error) {
if err != nil { if err != nil {
return "", fmt.Errorf("failed to load api tokens: %w", err) return "", fmt.Errorf("failed to load api tokens: %w", err)
} }
if len(apiTokens) == 0 { if apiTokens == nil {
apiTokens = nil apiTokens = []APITokenRecord{}
} }
// Load guest metadata (stored in data directory) // Load guest metadata (stored in data directory)
@ -99,7 +99,7 @@ func (c *ConfigPersistence) ExportConfig(passphrase string) (string, error) {
// Create export data // Create export data
exportData := ExportData{ exportData := ExportData{
Version: "4.0", Version: "4.1",
ExportedAt: time.Now(), ExportedAt: time.Now(),
Nodes: *nodes, Nodes: *nodes,
Alerts: *alertConfig, Alerts: *alertConfig,
@ -153,9 +153,13 @@ func (c *ConfigPersistence) ImportConfig(encryptedData string, passphrase string
} }
// Check version compatibility (warn but don't fail) // Check version compatibility (warn but don't fail)
if exportData.Version != "4.0" { switch exportData.Version {
// Log warning but continue - future versions might be compatible case "4.1", "":
fmt.Printf("Warning: Config was exported from version %s, current version is 4.0\n", exportData.Version) // current version, nothing to do
case "4.0":
fmt.Printf("Notice: Config was exported from version 4.0. API tokens were not included in that format.\n")
default:
fmt.Printf("Warning: Config was exported from unsupported version %s. Proceeding with best effort.\n", exportData.Version)
} }
// Import all configurations // Import all configurations
if err := c.SaveNodesConfig(exportData.Nodes.PVEInstances, exportData.Nodes.PBSInstances, exportData.Nodes.PMGInstances); err != nil { if err := c.SaveNodesConfig(exportData.Nodes.PVEInstances, exportData.Nodes.PBSInstances, exportData.Nodes.PMGInstances); err != nil {
@ -182,6 +186,16 @@ func (c *ConfigPersistence) ImportConfig(encryptedData string, passphrase string
return fmt.Errorf("failed to import system settings: %w", err) return fmt.Errorf("failed to import system settings: %w", err)
} }
// Import API tokens for newer export formats
if exportData.Version == "4.1" {
if exportData.APITokens == nil {
exportData.APITokens = []APITokenRecord{}
}
if err := c.SaveAPITokens(exportData.APITokens); err != nil {
return fmt.Errorf("failed to import api tokens: %w", err)
}
}
// Import OIDC configuration // Import OIDC configuration
if exportData.OIDC != nil { if exportData.OIDC != nil {
if err := c.SaveOIDCConfig(*exportData.OIDC); err != nil { if err := c.SaveOIDCConfig(*exportData.OIDC); err != nil {