75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
package backup
|
|
|
|
import (
|
|
"archive/zip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// FormatVersion / FormatName identify the backup archive format. They are
|
|
// byte-identical to the cms constants (backupFormatVersion / backupFormatName)
|
|
// so archives interoperate with the existing cms restore path.
|
|
FormatVersion = 3
|
|
FormatName = "blockninja-pgdump-backup"
|
|
)
|
|
|
|
// Source identifies where a backup came from. Field-for-field identical to the
|
|
// cms BackupSource JSON shape.
|
|
type Source struct {
|
|
SiteTitle string `json:"site_title"`
|
|
Domain string `json:"domain,omitempty"`
|
|
}
|
|
|
|
// Manifest is the metadata stored in manifest.json. It is a field-for-field copy
|
|
// of the cms BackupManifest so archives built here restore through the existing
|
|
// cms path unchanged.
|
|
type Manifest struct {
|
|
Version int `json:"version"`
|
|
Format string `json:"format"`
|
|
ExportedAt time.Time `json:"exported_at"`
|
|
Source Source `json:"source"`
|
|
DatabaseSize int64 `json:"database_size"`
|
|
MediaCount int `json:"media_count"`
|
|
BrandCount int `json:"brand_count,omitempty"`
|
|
IconsCount int `json:"icons_count,omitempty"`
|
|
StylesCount int `json:"styles_count,omitempty"`
|
|
PluginsCount int `json:"plugins_count,omitempty"`
|
|
Encryption *EncryptionParams `json:"encryption,omitempty"`
|
|
Checksum string `json:"checksum"` // SHA-256 of unencrypted database dump
|
|
}
|
|
|
|
// ReadManifest opens a backup zip archive and parses its manifest.json entry.
|
|
func ReadManifest(r io.ReaderAt, size int64) (*Manifest, error) {
|
|
zr, err := zip.NewReader(r, size)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open backup archive: %w", err)
|
|
}
|
|
|
|
for _, f := range zr.File {
|
|
if f.Name != "manifest.json" {
|
|
continue
|
|
}
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open manifest.json: %w", err)
|
|
}
|
|
defer rc.Close()
|
|
|
|
data, err := io.ReadAll(rc)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read manifest.json: %w", err)
|
|
}
|
|
|
|
var m Manifest
|
|
if err := json.Unmarshal(data, &m); err != nil {
|
|
return nil, fmt.Errorf("failed to parse manifest.json: %w", err)
|
|
}
|
|
return &m, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("manifest.json not found in backup archive")
|
|
}
|