Skip to content

0.16.0

Latest

Choose a tag to compare

@keven1024 keven1024 released this 05 Nov 02:05

v0.16 .0

Highlights

This release focuses on three major improvements:

  1. Statistics overhaul: Query metrics by time range.
  2. Security hardening: Strengthened notification and file-handling paths.
  3. Frontend dashboard improvements: Date-range filtering for statistics charts.

⚠️ Breaking Changes (Read Before Upgrading)

1. New required setting: share.session_salt

The Session Cookie signing key was previously hardcoded to "secret". It is now read from configuration:

share:
  # Required: Session Cookie signing key
  session_salt: your-session-salt

This field has validate:"required" validation. Existing config.yaml files without it will fail validation and prevent the service from starting. You must add this setting when upgrading.

Security note: The previous fixed signing key, "secret", could allow anyone aware of that default to forge Session Cookies. Generate a unique, cryptographically random value for each deployment.

2. Statistics storage migrated from a Redis Hash to four ZSets

Previously, a single Hash, 015:stat, stored cumulative file_size, file_num, share_num, and download_num fields. The new design uses sorted sets scored by timestamp:

ZSet key Member content
015:stat:file {file_size, file_id}
015:stat:share {share_id}
015:stat:download {share_id, ip}
015:stat:worker {task_id, task_type, status}

The new code only reads and writes these ZSets; it no longer reads the old 015:stat Hash.

Impact: Statistics on the About page will start accumulating from zero after the upgrade. Historical Hash values are no longer used. To retain historical totals, you must migrate the data yourself.

3. /api/stat changed from GET to POST

- {Method: []string{"GET"},  Path: "/stat", Handler: controllers.GetStat},
+ {Method: []string{"POST"}, Path: "/stat", Handler: controllers.GetStat},

Requests must now include a date range in the body. Update third-party scripts and older frontend clients that call this endpoint directly.

4. Share notifications are no longer retried

Webhook and email notifications are each attempted only once. Notification failures no longer return errors or trigger Asynq retries.

  • Previous behavior: Retry only if both notification channels failed.
  • New behavior: Do not retry failed notifications.

This change is intended to reduce the risk of SMTP providers flagging repeated attempts as abuse. Deployments requiring guaranteed delivery should implement their own compensating mechanism.

5. Default example domain changed

The example domain changed from fudaoyuan.icu to keven.fyi, affecting bg_url, about.*, about.email, and about.url in config.example.yaml, as well as the attribution link on the frontend About page. Update any example values carried over into your deployment.

6. pkg/utils.GetFileId signature changed

- func GetFileId(fileHash string, fileSize int64) string
+ func GetFileId(fileHash string, fileSize int64) (string, error)

A new VaildFileId validator requires file IDs to match:

^[0-9a-f]{40}_[0-9]+$

External code that directly imports pkg/utils must be updated. (VaildFileId is the identifier as provided in the change summary.)


🔒 Security Hardening

Webhook SSRF protection

File: worker/internal/services/notify.go

  • Validate URLs before sending: only http and https are allowed, and both a scheme and hostname are required.
  • Reject destinations resolving to private, loopback, link-local unicast, unspecified, or multicast IP addresses.
  • Disable redirects with resty.SetRedirectPolicy(resty.NoRedirectPolicy()) to prevent bypassing validation via HTTP 302 responses.
  • Allow only GET, POST, PUT, PATCH, and DELETE for Webhook methods; default to POST when unspecified.
  • Reject invalid methods when a share is created.

Email address validation

Every entry in NotifyEmails must be accepted by mail.ParseAddress; otherwise, return ErrInvalidRequest.

File ID validation

Add VaildFileId to reject malformed file IDs.

Restricted upload-directory access

Add u.GetUploadDir(), which returns *os.Root via os.OpenRoot. Backend and Worker operations for file chunks, merging, compression, and deletion now use a root-directory handle, reducing the risk of path traversal.

Centralized download-token parsing

File: backend/internal/services/download.go

Add ParseDownloadToken and DownloadShareClaims to validate the signing key, token validity, and nonempty share_id. Invalid tokens consistently return ErrInvalidDownloadToken.

Additional validity checks

Commit: e32a3e4

Add missing null and validity checks for file and share information in download.go, file.go, tasks/image.go, and tasks/share.go.


✨ New Features

Backend / Worker

1. Automatic cleanup of temporary upload chunks

Add the upload:remove task and RemoveUpload handler in worker/internal/tasks/upload.go and worker/internal/route.go.

For incomplete uploads in the FileTypeInit state:

  1. Calculate upload progress from uploaded chunks divided by total chunks.
  2. Calculate time progress from elapsed time divided by the validity period.
  3. If upload progress is ahead of half the time progress, treat the upload as active and recheck after 30 minutes.
  4. Otherwise, treat it as abandoned and immediately hand it off to file:remove for cleanup.
  5. Immediately clean up uploads with invalid metadata (Expire, ChunkSize, or FileSize less than or equal to zero).

Result: Interrupted and abandoned uploads no longer occupy disk space indefinitely.

2. Ordered file-chunk listing

Add GetFileSliceList in pkg/services/file.go, providing ordered chunk retrieval and error handling shared by cleanup decisions and merge operations.

3. Improved file removal

Optimize RemoveFile and introduce pkg/services/errors.go for consistent service-layer errors.

4. Worker statistics collection

Write timestamp-scored records to the corresponding ZSets during download, sharing, upload, and task-processing operations, enabling time-range queries.

Frontend

1. Date-range picker

Add DateRangePicker.vue and Field/DateRangePickerField.vue, along with the ui/range-calendar/ component family:

Component Purpose
RangeCalendar Date-range calendar
RangeCalendarCell Date cell
RangeCalendarCellTrigger Date-cell trigger
RangeCalendarGrid Calendar grid
RangeCalendarGridBody Grid body
RangeCalendarGridHead Grid header
RangeCalendarGridRow Grid row
RangeCalendarHeadCell Header cell
RangeCalendarHeader Calendar header
RangeCalendarHeading Calendar heading
RangeCalendarNextButton Next-period button
RangeCalendarPrevButton Previous-period button
index.ts Component exports

2. Date-range filtering for the statistics dashboard

File: About/AboutChartView.vue

  • Accept selected date ranges in statistics queries.
  • Introduce the DateRangeOption type.
  • Read aggregate totals from the latest data source for accuracy.
  • Calculate the Y-axis domain.
  • Improve data display and unit conversion.

3. Development-page visualizations

File: pages/dev.vue

Add a file-upload progress view and heatmap visualization components.

4. New runtime dependencies

Add @internationalized/date and cn.


🐛 Bug Fixes

Area Fix
Redis statistics range queries Correct ZSet score and member retrieval (016537c).
Aggregate statistics Read totals from the latest data source (fa5eb3d).
CI prepare script Run the prepare script only outside CI environments.
Worker error logging Correctly log RemoveShare and ShareNotify errors with zap.
vue-sonner type checking Work around incorrect template unwrapping in vue-tsc using @ts-ignore.
Graph rendering Fix status color assignment.
Example links Standardize background-image and example-link domains.

🔧 Refactoring and Engineering Improvements

Backend

  • Refactor backend file processing to consistently use os.Root.
  • Improve file-chunk merging and archive generation.
  • Refactor statistics processing with better grouping, simpler code using MapValues, and streamlined labels and calculations.

Tests

Move coverage from backend/internal/services/file_test.go to pkg/services/file_test.go, adding 46 lines of tests.

Frontend tooling

  • Change upload visualization events from @render to @effect.
  • Format the vue-query plugin code.
  • Add the following setting to .vscode/settings.json:
{
  "js/ts.experimental.useTsgo": false
}

Build scripts

In the root package.json:

  • Split prepare into prepare:git (husky) and prepare:backend (go install github.com/air-verse/air@latest), executed in parallel.
  • Append go mod tidy after go get -u in every up-deps:* script.

📦 Dependency Updates

Go

Module Previous New
github.com/labstack/echo/v5 v5.4.0 v5.4.4
github.com/klauspost/compress v1.20.1 v1.20.3
github.com/openai/openai-go/v3 v3.74.0 v3.91.0
github.com/redis/rueidis v1.0.78 v1.0.79
golang.org/x/crypto v0.57.0 v0.58.0
golang.org/x/net v0.59.0 v0.62.0
golang.org/x/sys v0.48.0 v0.49.0
golang.org/x/text v0.42.0 v0.43.0
github.com/gabriel-vasile/mimetype v1.4.15 v1.4.16
go.yaml.in/yaml/v3 v3.0.5 v3.0.6
github.com/samber/lo — v1.53.0 (new direct dependency)
github.com/hibiken/asynq — v0.26.0 (direct dependency in pkg/services)
github.com/stretchr/testify — v1.12.1 (direct dependency in pkg/services)

Frontend / Node

Package Previous New
vue ^3.5.43 ^3.5.44
@tiptap/* ^3.31.4 ^3.32.1
@lucide/vue ^1.52.0 ^1.63.0
@tanstack/vue-query ^5.104.1 ^5.105.0
@nuxt/image ^2.1.0 ^2.2.0
axios ^1.20.0 ^1.21.0
motion-v ^2.6.0 ^2.9.0
shadcn ^4.21.4 ^4.23.0
shadcn-nuxt ^2.8.2 ^2.9.0
file-type ^22.1.1 ^22.2.0
filesize ^11.0.25 ^11.0.29
heic-to ^1.6.5 ^1.6.7
vue3-pixi ^1.0.2 ^1.0.3
vue3-pixi-nuxt ^1.0.2 ^1.0.3
vitest ^4.1.11 ^4.1.12
vue-tsc ^3.3.12 ^3.3.13
concurrently (dev) ^9.2.4 ^9.2.5
prettier (dev) ^3.9.9 ^3.9.10

New direct dependencies: @internationalized/date ^3.12.4 and cn ^0.5.1.

Lockfile changes: pnpm-lock.yaml: +1,591 / −2,404 lines; go.work.sum: +18 lines.


🚀 Upgrade Guide

1. Update your configuration

Back up config.yaml and add session_salt under share:

share:
  session_salt: your-random-session-salt

For example, generate a random value with:

openssl rand -hex 32

Without this setting, the service will not start.

2. Review example domains

Replace any inherited fudaoyuan.icu example values in bg_url, about.url, and about.email as needed.

3. Plan statistics migration

The old 015:stat Hash is no longer read. Metrics will begin accumulating again after the upgrade. Export and migrate the old Hash data into the new ZSets if historical totals must be preserved.

4. Review Redis configuration

The following new ZSet keys are used:

015:stat:file
015:stat:share
015:stat:download
015:stat:worker

Review any Redis key-count, memory, and expiration limits.

5. Update /api/stat clients

Change external requests from GET to POST and include a date range in the request body.

6. Review Webhook settings

Webhook targets must resolve to public IP addresses. Private, loopback, link-local, and other restricted destinations are rejected. Confirm that configured HTTP methods are allowed.

7. Reinstall dependencies

pnpm install

Run the relevant up-deps:* scripts as needed to synchronize Go modules.

8. Test notification delivery

Because notifications are no longer retried, verify in a test environment that Webhook and email delivery work and that failures do not trigger Asynq retries.


✅ Recommended Verification Checklist

  • The service starts successfully after adding session_salt.
  • Missing session_salt correctly prevents startup through configuration validation.
  • Temporary chunks from an interrupted large upload are removed after the cleanup window.
  • The upload:remove task executes correctly.
  • About-page charts show correct data when changing date ranges.
  • Chart Y-axis scales and unit conversions are reasonable.
  • A Webhook targeting a private address such as http://127.0.0.1:8080/hook is rejected.
  • Unsupported Webhook HTTP methods are rejected.
  • Share-password, share-claiming, and expired download-token flows return appropriate errors.
  • File uploads, chunk merging, compression, and deletion work correctly.
  • Failed Webhook and email notifications are not retried.

015 v0.16 — A redesigned statistics system, stronger security, and an improved frontend experience.

New Contributors

Full Changelog: 0.15.0...0.16.0