Files
MosisService/portal/cmd/mosis/cmd/sign.go

158 lines
3.8 KiB
Go

package cmd
import (
"archive/zip"
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"omixlab.com/mosis-portal/pkg/mospkg"
)
// SignCmd returns the sign command
func SignCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "sign <package>",
Short: "Sign a .mosis package",
Long: "Sign a Mosis package with your Ed25519 developer key.",
Args: cobra.ExactArgs(1),
RunE: runSign,
}
cmd.Flags().StringP("key", "k", "", "Path to private key (default: ~/.mosis/signing_key.pem)")
cmd.Flags().Bool("verify", false, "Verify existing signature instead of signing")
cmd.Flags().StringP("output", "o", "", "Output path (default: overwrite input)")
return cmd
}
func runSign(cmd *cobra.Command, args []string) error {
packagePath := args[0]
// Check package exists
if _, err := os.Stat(packagePath); os.IsNotExist(err) {
return fmt.Errorf("package not found: %s", packagePath)
}
// Verify mode
verify, _ := cmd.Flags().GetBool("verify")
if verify {
return verifyPackage(cmd, packagePath)
}
// Sign mode
keyPath, _ := cmd.Flags().GetString("key")
if keyPath == "" {
keyPath = filepath.Join(ConfigDir(), "signing_key.pem")
}
// Load private key
keyData, err := os.ReadFile(keyPath)
if err != nil {
return fmt.Errorf("failed to read key: %s\n\nGenerate a key with: mosis keys generate", keyPath)
}
privateKey, err := mospkg.LoadPrivateKey(keyData)
if err != nil {
return fmt.Errorf("invalid key: %w", err)
}
// Get public key fingerprint
publicKey := privateKey.Public().(interface{ Bytes() []byte })
fingerprint := mospkg.PublicKeyFingerprint(publicKey.Bytes())
fmt.Printf("Using key: %s\n", keyPath)
fmt.Printf("Fingerprint: %s\n\n", fingerprint)
// Determine output path
output, _ := cmd.Flags().GetString("output")
if output == "" {
// Sign in place by creating temp file
output = packagePath + ".signed"
}
// Generate manifest and sign
fmt.Println("Generating file hashes...")
fmt.Println("Signing MANIFEST.MF...")
if err := mospkg.SignPackage(packagePath, output, privateKey); err != nil {
return fmt.Errorf("sign package: %w", err)
}
// If signing in place, replace original
if output == packagePath+".signed" {
if err := os.Rename(output, packagePath); err != nil {
return fmt.Errorf("replace original: %w", err)
}
output = packagePath
}
// Count files in package
fileCount := countPackageFiles(output)
fmt.Printf("\n✓ Package signed: %s\n", output)
fmt.Println("\nSignature details:")
fmt.Println(" Algorithm: Ed25519")
fmt.Printf(" Key fingerprint: %s\n", fingerprint)
fmt.Printf(" Files signed: %d\n", fileCount)
return nil
}
func verifyPackage(cmd *cobra.Command, packagePath string) error {
keyPath, _ := cmd.Flags().GetString("key")
// Try to load public key
var pubKeyPath string
if keyPath != "" {
pubKeyPath = keyPath
} else {
// Try default locations
pubKeyPath = filepath.Join(ConfigDir(), "signing_key.pub")
}
keyData, err := os.ReadFile(pubKeyPath)
if err != nil {
return fmt.Errorf("public key not found: %s\n\nProvide key with --key flag", pubKeyPath)
}
publicKey, err := mospkg.LoadPublicKey(keyData)
if err != nil {
return fmt.Errorf("invalid public key: %w", err)
}
fmt.Printf("Verifying: %s\n", packagePath)
fmt.Printf("Using key: %s\n\n", pubKeyPath)
valid, err := mospkg.VerifyPackageSignature(packagePath, publicKey)
if err != nil {
return fmt.Errorf("verification failed: %w", err)
}
if valid {
fmt.Println("✓ Signature is valid")
fmt.Println("✓ All file hashes match")
return nil
}
return fmt.Errorf("✗ Signature verification failed")
}
func countPackageFiles(path string) int {
reader, err := zip.OpenReader(path)
if err != nil {
return 0
}
defer reader.Close()
count := 0
for _, f := range reader.File {
if !f.FileInfo().IsDir() {
count++
}
}
return count
}