Skip to content

fix: recognize KeeOTP TOTP query fields #9

Description

@ftorga

Problem

KeeForge does not recognize some valid KeePass OTP entries. In particular, the KeeOTP plugin stores TOTP configuration in the custom otp field as a query string instead of an otpauth:// URI:

otp=key=<secret>&type=TOTP&step=30&size=6&encoding=Base32&otpHashMode=SHA1

When this value is opened in KeeForge, no totpConfig is created and the OTP section is not shown.

First implementation slice

This change targets KeeOTP TOTP compatibility:

  • custom fields named exactly otp, OTP, or Otp;
  • values beginning with key=;
  • URL-query decoding;
  • strict support for the KeeOTP encodings Base32, Base64, Hex, and UTF8;
  • explicit validation of type=TOTP, step, size, and otpHashMode;
  • no decoder fallback or heuristic interpretation;
  • preservation of existing OTP source precedence and behavior;
  • regression coverage for malformed values, duplicate parameters, encoding boundaries, and lowercase Base32 keys.

HOTP is intentionally deferred to a separate change because it requires a mutable counter, persistence, conflict handling, and one-shot generation semantics.

Compatibility evidence

The KeeOtp2 implementation confirms:

  • legacy data is stored in the otp field;
  • supported parameters include key, type, step, size, encoding, counter, and otpHashMode;
  • KeeOtp2 accepts Base32 keys in lowercase;
  • HOTP uses a separate counter lifecycle and is outside this first slice.

Reference: KeeOtp2

Verification

The implementation includes focused XCTest coverage. Local verification is pending because xcodebuild is unavailable on Linux. The repository CI workflow runs on macos-15 with Xcode and can validate the change there.

Follow-up candidates

  • HOTP support with persistent counter / HmacOtp-Counter.
  • OTP URIs stored in the standard URL field.
  • Additional URI schemes such as otp://, after establishing a verified compatibility baseline.
  • Raw Base32-only values without explicit KeeOTP query metadata.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions