Skip to content

feat(upload): add voided.host uploaders with shared config and settings UI - #480

Open
Lixqa wants to merge 1 commit into
SnapXL:developfrom
Lixqa:develop
Open

feat(upload): add voided.host uploaders with shared config and settings UI#480
Lixqa wants to merge 1 commit into
SnapXL:developfrom
Lixqa:develop

Conversation

@Lixqa

@Lixqa Lixqa commented May 22, 2026

Copy link
Copy Markdown

Preface

SnapX did not have a built-in voided.host destination. voided.host supports image, text, and file uploads through one shared upload key, so adding it means implementing shared upload logic rather than three unrelated uploaders.

This change adds voided.host as a first-class SnapX uploader with encrypted config, AOT-friendly JSON parsing, and Avalonia settings UI.

Description of Change

Adds voided.host as a built-in uploader for image, text, and file destinations.

Core (SnapX.Core):

  • Adds VoidedHost to ImageDestination, TextDestination, and FileDestination
  • Adds VoidedHostUploadKey (encrypted) and VoidedHostUseGuest to UploadersConfig
  • Implements VoidedHostUploader (images) with shared VoidedHostMultipartUploader and VoidedHostResponseParser
  • Implements VoidedHostTextUploader (pastes) and VoidedHostFileUploader (files)
  • Registers all three services in UploaderFactory
  • Adds UniversalUploaders to UploaderCategory for settings navigation
  • Adds [voided.host] debug logging for upload requests and API responses (status code, body preview, parse errors)

UI (SnapX.Avalonia):

  • Adds a Universal uploaders section under Destinations with a single voided.host settings page instead of three duplicate entries
  • Adds VoidedHostUploaderSettingsView for guest mode, upload key, and links to register or manage keys
  • Wires the settings view in BuiltInUploaderSettingsView for all three voided.host uploader types

Uploads use multipart requests to api.voided.host with Authorization header auth, optional guest mode, and structured JSON error handling.

Possible Alternatives

Separate settings pages per destination type: rejected because voided.host uses one upload key for images, pastes, and files. Three pages would duplicate the same controls.

Single uploader class for all three types: rejected to stay consistent with SnapX's existing pattern of separate image, text, and file services, while sharing logic through VoidedHostMultipartUploader.

Implementation Details

Upload logic lives in VoidedHostMultipartUploader, which all three uploaders delegate to with different API URLs:

Image: https://api.voided.host/v2/images
Text: https://api.voided.host/v2/pastes
File: https://api.voided.host/v2/files

Multipart fields use p=snapx, v=1, and a timestamp. Guest mode is enabled when VoidedHostUseGuest is true and a guest API key is present in the build.

Settings are grouped under Universal uploaders because the configuration is destination-agnostic. voided.host still appears separately in the image, text, and file destination pickers when choosing where to upload.

Notes

  • Guest upload depends on GuestUploadApiKey being set at build time. If it is empty, guest mode is disabled in the UI and CheckConfig requires a personal upload key.
  • Debug logs use the [voided.host] prefix and include HTTP status codes and truncated response bodies to help diagnose API issues.
  • UploaderFactory.cs was updated manually. Regenerating via the build tool will re-include the new services automatically.

Tested on

  • Windows — Version: 10.0.19045
  • Linux — Distro & Version: N/A
  • macOS — Version: N/A
  • FreeBSD (optional) — Details: N/A

Greptile Summary

This PR adds voided.host as a shared image, text, and file destination with encrypted personal-key configuration and an Avalonia settings page. It also:

  • Registers image, text, and file uploader services and destination enum values.
  • Implements shared multipart request and JSON response handling.
  • Adds a universal uploader settings category for the shared account configuration.
  • Introduces guest uploads through a bundled shared authorization key.

Confidence Score: 3/5

This PR should not merge until the exposed shared guest credential is revoked and replaced with a design that does not distribute a reusable secret to clients.

The guest upload path embeds a reusable authorization value in public source, returns it as the effective upload key, and sends it directly to all three upload endpoints, allowing external abuse of the shared identity.

Files Needing Attention: SnapX.Core/Upload/Img/VoidedHostUploader.cs

Security Review

The guest authorization credential is committed directly in source and transmitted as a bearer-style Authorization value. Anyone with the source or a distributed binary can reuse it outside SnapX to upload content under the shared guest identity. How this was verified: The constant returned by the guest-key selection path is passed verbatim into the multipart request's Authorization header.

Important Files Changed

Filename Overview
SnapX.Core/Upload/Img/VoidedHostUploader.cs Implements shared multipart transport, guest-key selection, and response parsing, but exposes the reusable guest authorization credential in public source and binaries.
SnapX.Core/Upload/Text/VoidedHostTextUploader.cs Adds a text-upload wrapper that converts text to UTF-8 multipart content and delegates to the shared transport.
SnapX.Core/Upload/File/VoidedHostFileUploader.cs Adds a file-upload wrapper with shared transport, progress forwarding, and cancellation delegation.
SnapX.Avalonia/Views/Settings/Views/ImageUploaders/VoidedHostUploaderSettingsView.axaml.cs Connects shared guest-mode and personal-key controls to the global voided.host configuration.
SnapX.Core/Upload/UploaderFactory.cs Registers all three new voided.host service implementations in their corresponding destination maps.
SnapX.Core/Upload/UploadersConfig.cs Adds encrypted personal upload-key storage and a shared guest-mode preference.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    UI[voided.host settings] --> Config[Shared UploadersConfig]
    Config --> Factory[UploaderFactory]
    Factory --> Image[Image uploader]
    Factory --> Text[Text uploader]
    Factory --> File[File uploader]
    Image --> Multipart[Shared multipart uploader]
    Text --> Multipart
    File --> Multipart
    Config -->|Guest mode| GuestKey[Bundled guest key]
    Config -->|Personal mode| PersonalKey[Encrypted personal key]
    GuestKey --> Multipart
    PersonalKey --> Multipart
    Multipart --> API[api.voided.host]
    API --> Parser[Shared JSON response parser]
Loading

Reviews (1): Last reviewed commit: "feat(upload): add voided.host uploaders ..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@github-actions github-actions Bot added Avalonia Related to SnapX.Avalonia Core Related to SnapX.Core labels May 22, 2026
@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 22 critical · 3 high · 16 medium · 3 minor

Alerts:
⚠ 44 issues (≤ 0 issues of at least minor severity)

Results:
44 new issues

Category Results
Compatibility 4 medium
BestPractice 7 medium
ErrorProne 20 critical
1 high
Security 2 critical
2 high
CodeStyle 3 minor
Complexity 5 medium

View in Codacy

🟢 Metrics 100 complexity · 8 duplication

Metric Results
Complexity 100
Duplication 8

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@BrycensRanch

BrycensRanch commented Aug 8, 2026

Copy link
Copy Markdown
Member

Hi, thanks for submitting a PR. I was initially considering closing this because I'm still hesitant to add any uploaders I don't personally know yet. Considering that it isn't in https://github.com/SnapXL/CustomUploaders. However, I do appreciate the initiative. I looked into your host more, and it seems to have been around for more than a summer, so that's good. Since you're providing anonymous uploads for SnapX users, I'm down to approve this, provided you fix up this PR by removing the UniversalUploader type (no other uploader uses this).

The next version of SnapX is the rewrite. No more changes on develop are being made. Currently, the rewrite branch is only on my local machine. When the rewrite hits develop, I will adapt this PR to it.

Also, while our CONTRIBUTING.md doesn't explicitly mention it, AI disclosure is required for contributions.

@BrycensRanch BrycensRanch added enhancement New feature or request waiting-on-op Waiting for original poster to respond labels Aug 8, 2026
@Lixqa

Lixqa commented Aug 9, 2026

Copy link
Copy Markdown
Author

Hi @BrycensRanch, I added UniversalUploader because voided.host uses a single configuration for images, pastes, and files. Without it, users would have to configure all three separately and update each configuration whenever they want to change their upload settings.

If you'd prefer the existing design, let me know and I'll remove UniversalUploader.

@BrycensRanch BrycensRanch removed the waiting-on-op Waiting for original poster to respond label Aug 20, 2026
/// for the shared guest account. Guest mode stays off in the UI and in CheckConfig until this is non-empty.
/// Omit from public repos — set at release build time only.
/// </summary>
public const string GuestUploadApiKey = "MTA3NQ.MTc3ODMzMzE1MDI3NA.wIeJFNAwaYymgvgMIhLCxRamvUXWtZMtSGmjQNZDfGDKGVqx";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Shared guest credential is exposed

Anyone with the public source or a distributed binary can extract GuestUploadApiKey and submit image, paste, or file uploads directly under SnapX's shared guest identity, causing quota abuse or credential revocation that disables guest uploads for all users. How this was verified: The guest-key selection path returns this constant and the multipart uploader passes it verbatim in the Authorization header.

@BrycensRanch

Copy link
Copy Markdown
Member

Ignore the review; I am testing new tools that can assist in code review.

Anything it suggests I'll be fixing myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Avalonia Related to SnapX.Avalonia Core Related to SnapX.Core enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants