mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
699e95f12c
Result: {"status":"keep","total_issues":56,"golint_canonicalheader":8,"golint_errname":1,"golint_errorlint":12,"golint_forcetypeassert":3,"golint_gosec":0,"golint_intrange":3,"golint_modernize":5,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":55,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":47}
192 lines
5.2 KiB
Go
192 lines
5.2 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package pagesarchive provides multi-format archive detection, inspection and
|
|
// extraction helpers for OpenFlare Pages deployment packages.
|
|
package pagesarchive
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// Format identifies a supported Pages deployment package archive format.
|
|
type Format string
|
|
|
|
const (
|
|
// FormatZip is a ZIP archive.
|
|
FormatZip Format = "zip"
|
|
// FormatTar is an uncompressed tar archive.
|
|
FormatTar Format = "tar"
|
|
// FormatTarGz is a gzip-compressed tar archive.
|
|
FormatTarGz Format = "tar.gz"
|
|
// FormatTarXz is an xz-compressed tar archive.
|
|
FormatTarXz Format = "tar.xz"
|
|
// FormatTarBz2 is a bzip2-compressed tar archive.
|
|
FormatTarBz2 Format = "tar.bz2"
|
|
// FormatSevenZip is a 7z archive.
|
|
FormatSevenZip Format = "7z"
|
|
|
|
ustarMagicOffset = 257
|
|
ustarMagicMinLen = 262
|
|
)
|
|
|
|
// DetectFormatFromName returns the archive format inferred from a file name.
|
|
// Returns an empty Format and false when the extension is unsupported.
|
|
func DetectFormatFromName(fileName string) (Format, bool) {
|
|
name := strings.ToLower(strings.TrimSpace(fileName))
|
|
switch {
|
|
case strings.HasSuffix(name, ".tar.gz"), strings.HasSuffix(name, ".tgz"):
|
|
return FormatTarGz, true
|
|
case strings.HasSuffix(name, ".tar.xz"), strings.HasSuffix(name, ".txz"):
|
|
return FormatTarXz, true
|
|
case strings.HasSuffix(name, ".tar.bz2"), strings.HasSuffix(name, ".tbz2"), strings.HasSuffix(name, ".tbz"):
|
|
return FormatTarBz2, true
|
|
case strings.HasSuffix(name, ".tar"):
|
|
return FormatTar, true
|
|
case strings.HasSuffix(name, ".7z"):
|
|
return FormatSevenZip, true
|
|
case strings.HasSuffix(name, ".zip"):
|
|
return FormatZip, true
|
|
default:
|
|
return "", false
|
|
}
|
|
}
|
|
|
|
// DetectFormatFromBytes returns the archive format inferred from magic bytes.
|
|
// Prefer DetectFormatFromName when a reliable file name is available.
|
|
func DetectFormatFromBytes(data []byte) (Format, bool) {
|
|
if isZipMagic(data) {
|
|
return FormatZip, true
|
|
}
|
|
if isSevenZipMagic(data) {
|
|
return FormatSevenZip, true
|
|
}
|
|
if isXZMagic(data) {
|
|
return FormatTarXz, true
|
|
}
|
|
if isGzipMagic(data) {
|
|
return FormatTarGz, true
|
|
}
|
|
if isBzip2Magic(data) {
|
|
return FormatTarBz2, true
|
|
}
|
|
if looksLikeTar(data) {
|
|
return FormatTar, true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
// DetectFormat prefers the file name when present, otherwise magic bytes.
|
|
func DetectFormat(fileName string, data []byte) (Format, error) {
|
|
if format, ok := DetectFormatFromName(fileName); ok {
|
|
return format, nil
|
|
}
|
|
if format, ok := DetectFormatFromBytes(data); ok {
|
|
return format, nil
|
|
}
|
|
return "", errors.New("unsupported pages package format")
|
|
}
|
|
|
|
// Extension returns the canonical file extension for a format (without leading dot).
|
|
func Extension(format Format) string {
|
|
switch format {
|
|
case FormatZip:
|
|
return "zip"
|
|
case FormatTar:
|
|
return "tar"
|
|
case FormatTarGz:
|
|
return "tar.gz"
|
|
case FormatTarXz:
|
|
return "tar.xz"
|
|
case FormatTarBz2:
|
|
return "tar.bz2"
|
|
case FormatSevenZip:
|
|
return "7z"
|
|
default:
|
|
return "bin"
|
|
}
|
|
}
|
|
|
|
// MIMEType returns a reasonable content type for the archive format.
|
|
func MIMEType(format Format) string {
|
|
switch format {
|
|
case FormatZip:
|
|
return "application/zip"
|
|
case FormatTar:
|
|
return "application/x-tar"
|
|
case FormatTarGz:
|
|
return "application/gzip"
|
|
case FormatTarXz:
|
|
return "application/x-xz"
|
|
case FormatTarBz2:
|
|
return "application/x-bzip2"
|
|
case FormatSevenZip:
|
|
return "application/x-7z-compressed"
|
|
default:
|
|
return "application/octet-stream"
|
|
}
|
|
}
|
|
|
|
// SupportedExtensions lists human-readable extensions for UI copy and accept attributes.
|
|
func SupportedExtensions() []string {
|
|
return []string{".zip", ".tar.gz", ".tgz", ".tar.xz", ".txz", ".tar.bz2", ".tbz2", ".tar", ".7z"}
|
|
}
|
|
|
|
// AcceptAttribute returns a comma-separated accept list for file inputs.
|
|
func AcceptAttribute() string {
|
|
return strings.Join(SupportedExtensions(), ",")
|
|
}
|
|
|
|
// NormalizeNameExtension returns a storage-safe extension for the given format/name.
|
|
func NormalizeNameExtension(fileName string, format Format) string {
|
|
if format != "" {
|
|
return Extension(format)
|
|
}
|
|
if formatFromName, ok := DetectFormatFromName(fileName); ok {
|
|
return Extension(formatFromName)
|
|
}
|
|
ext := strings.TrimPrefix(filepath.Ext(fileName), ".")
|
|
if ext == "" {
|
|
return "bin"
|
|
}
|
|
return strings.ToLower(ext)
|
|
}
|
|
|
|
func isZipMagic(data []byte) bool {
|
|
return len(data) >= 4 &&
|
|
data[0] == 0x50 && data[1] == 0x4b &&
|
|
(data[2] == 0x03 || data[2] == 0x05 || data[2] == 0x07) &&
|
|
(data[3] == 0x04 || data[3] == 0x06 || data[3] == 0x08)
|
|
}
|
|
|
|
func isSevenZipMagic(data []byte) bool {
|
|
return len(data) >= 6 &&
|
|
data[0] == 0x37 && data[1] == 0x7a && data[2] == 0xbc &&
|
|
data[3] == 0xaf && data[4] == 0x27 && data[5] == 0x1c
|
|
}
|
|
|
|
func isXZMagic(data []byte) bool {
|
|
return len(data) >= 6 &&
|
|
data[0] == 0xfd && data[1] == 0x37 && data[2] == 0x7a &&
|
|
data[3] == 0x58 && data[4] == 0x5a && data[5] == 0x00
|
|
}
|
|
|
|
func isGzipMagic(data []byte) bool {
|
|
return len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b
|
|
}
|
|
|
|
func isBzip2Magic(data []byte) bool {
|
|
return len(data) >= 3 && data[0] == 0x42 && data[1] == 0x5a && data[2] == 0x68
|
|
}
|
|
|
|
func looksLikeTar(data []byte) bool {
|
|
// POSIX ustar magic at offset 257 ("ustar\0" or "ustar ").
|
|
if len(data) < ustarMagicMinLen {
|
|
return false
|
|
}
|
|
return bytes.Equal(data[ustarMagicOffset:ustarMagicOffset+5], []byte("ustar"))
|
|
}
|