Compare commits

...

11 commits

Author SHA1 Message Date
Evan Su
670d284603
Merge pull request #89 from Retengart/test-features
Some checks failed
build-linux / build (push) Has been cancelled
build-macos / build (push) Has been cancelled
build-windows / build (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
App version in the window title and zip unpacking
2025-01-29 11:02:44 -05:00
Alex Verner
445cd48e53 fix: delete a partially extracted file if run out of space 2025-01-28 12:22:19 +03:00
Alex Verner
46b557e3ef update date 2025-01-28 01:50:17 +03:00
Evan Su
47b65d6fe0 return err on ".." in zip item file path
Unlikely to happen since go stdlib zip doesn't do it, so if it does happen, better safe than sorry.
2025-01-27 01:12:14 -05:00
Evan Su
a929eb1037 final auto unzip code tweaks 2025-01-27 00:55:47 -05:00
Evan Su
bf73698c52 update unpackArchive to use both flags
also remove comments that add no value
2025-01-27 00:32:03 -05:00
Evan Su
10e8a1af82 auto unzip: careful ui state handling 2025-01-27 00:13:11 -05:00
Alex Verner
525ee4d591 flatpak metainfo to 1.46 2025-01-26 01:46:12 +03:00
Alex Verner
af3e1748fb Bump to 1.46: zip unpacking and version in title 2025-01-26 01:05:40 +03:00
Alex Verner
fee796845b zip unpacking with status bar 2025-01-25 22:59:41 +03:00
Alex Verner
fdebb502ab unpack zip and version in the window title 2025-01-25 22:12:14 +03:00
4 changed files with 151 additions and 7 deletions

View file

@ -3,6 +3,12 @@
<li>Migrate golang.org/x/crypto to standard library imports (https://github.com/golang/go/issues/65269)</li>
</ul>
# v1.46 (Released 01/29/2025)
<ul>
<li>✓ Added Picocrypt version to the window title</li>
<li>✓ Added ability to automatically unzip archives upon decryption</li>
</ul>
# v1.45 (Released 12/05/2024)
<ul>
<li>✓ Bumped GitHub Actions Ubuntu 22 -> 24 and macOS 14 -> 15</li>

View file

@ -1 +1 @@
1.45
1.46

View file

@ -44,11 +44,17 @@
</screenshot>
</screenshots>
<releases>
<release version="1.45" date="2024-12-05">
<url type="details">https://github.com/Picocrypt/Picocrypt/blob/main/Changelog.md#v145-released-12052024</url>
<release version="1.46" date="2025-01-29">
<url type="details">https://github.com/Picocrypt/Picocrypt/blob/main/Changelog.md#v146-released-01292025</url>
<description>
<p>No code changes; just updated dependencies.</p>
<ul>
<li>Added Picocrypt version to the window title.</li>
<li>Added ability to automatically unpack zip archives during decryption.</li>
</ul>
</description>
</release>
<release version="1.45" date="2024-12-05">
<description></description>
</release>
</releases>
</component>

View file

@ -2,7 +2,7 @@ package main
/*
Picocrypt v1.45
Picocrypt v1.46
Copyright (c) Evan Su
Released under a GNU GPL v3 License
https://github.com/Picocrypt/Picocrypt
@ -60,7 +60,7 @@ var TRANSPARENT = color.RGBA{0x00, 0x00, 0x00, 0x00}
// Generic variables
var window *giu.MasterWindow
var version = "v1.45"
var version = "v1.46"
var dpi float32
var mode string
var working bool
@ -120,6 +120,8 @@ var splitSelected int32 = 1
var recombine bool
var compress bool
var delete bool
var autoUnzip bool
var sameLevel bool
var keep bool
var kept bool
@ -552,6 +554,22 @@ func draw() {
giu.Checkbox("Delete volume", &delete),
giu.Tooltip("Delete the volume after a successful decryption"),
).Build()
giu.Row(
giu.Style().SetDisabled(!strings.HasSuffix(inputFile, ".zip.pcv")).To(
giu.Checkbox("Auto unzip", &autoUnzip).OnChange(func() {
if !autoUnzip {
sameLevel = false
}
}),
giu.Tooltip("Extract .zip upon decryption (may overwrite)"),
),
giu.Dummy(-170, 0),
giu.Style().SetDisabled(!autoUnzip).To(
giu.Checkbox("Same level", &sameLevel),
giu.Tooltip("Extract .zip contents to same folder as volume"),
),
).Build()
}
}),
@ -2112,6 +2130,21 @@ func work() {
os.Remove(inputFile)
}
if mode == "decrypt" && !kept && autoUnzip {
showProgress = true
popupStatus = "Unzipping..."
giu.Update()
if err := unpackArchive(outputFile); err != nil {
mainStatus = "Auto unzipping failed!"
mainStatusColor = RED
giu.Update()
return
}
os.Remove(outputFile)
}
// All done, reset the UI
oldKept := kept
resetUI()
@ -2209,6 +2242,8 @@ func resetUI() {
recombine = false
compress = false
delete = false
autoUnzip = false
sameLevel = false
keep = false
kept = false
@ -2330,9 +2365,106 @@ func sizeify(size int64) string {
}
}
func unpackArchive(zipPath string) error {
reader, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer reader.Close()
var totalSize int64
for _, f := range reader.File {
totalSize += int64(f.UncompressedSize64)
}
var extractDir string
if sameLevel {
extractDir = filepath.Dir(zipPath)
} else {
extractDir = filepath.Join(filepath.Dir(zipPath), strings.TrimSuffix(filepath.Base(zipPath), ".zip"))
}
var done int64
startTime := time.Now()
for _, f := range reader.File {
if strings.Contains(f.Name, "..") {
return errors.New("potentially malicious zip item path")
}
outPath := filepath.Join(extractDir, f.Name)
// Make directory if current entry is a folder
if f.FileInfo().IsDir() {
if err := os.MkdirAll(outPath, f.Mode()); err != nil {
return err
}
}
}
for i, f := range reader.File {
if strings.Contains(f.Name, "..") {
return errors.New("potentially malicious zip item path")
}
// Already handled above
if f.FileInfo().IsDir() {
continue
}
outPath := filepath.Join(extractDir, f.Name)
// Otherwise create necessary parent directories
if err := os.MkdirAll(filepath.Dir(outPath), 0755); err != nil {
return err
}
// Open the file inside the archive
fileInArchive, err := f.Open()
if err != nil {
return err
}
defer fileInArchive.Close()
dstFile, err := os.Create(outPath)
if err != nil {
return err
}
// Read from zip in chunks to update progress
buffer := make([]byte, MiB)
for {
n, readErr := fileInArchive.Read(buffer)
if n > 0 {
_, writeErr := dstFile.Write(buffer[:n])
if writeErr != nil {
dstFile.Close()
os.Remove(dstFile.Name())
return writeErr
}
done += int64(n)
progress, speed, eta = statify(done, totalSize, startTime)
progressInfo = fmt.Sprintf("%d/%d", i+1, len(reader.File))
popupStatus = fmt.Sprintf("Unpacking at %.2f MiB/s (ETA: %s)", speed, eta)
giu.Update()
}
if readErr != nil {
if readErr == io.EOF {
break
}
dstFile.Close()
return readErr
}
}
dstFile.Close()
}
return nil
}
func main() {
// Create the main window
window = giu.NewMasterWindow("Picocrypt", 318, 507, giu.MasterWindowFlagsNotResizable)
window = giu.NewMasterWindow("Picocrypt "+version[1:], 318, 507, giu.MasterWindowFlagsNotResizable)
// Start the dialog module
dialog.Init()