Skip to content

Refactor: Extract Application from the shared actor pipeline#2926

Draft
pfefferle wants to merge 13 commits into
trunkfrom
refactor/extract-application-from-actor-system
Draft

Refactor: Extract Application from the shared actor pipeline#2926
pfefferle wants to merge 13 commits into
trunkfrom
refactor/extract-application-from-actor-system

Conversation

@pfefferle

Copy link
Copy Markdown
Member

Fixes #

Proposed changes:

  • Extract the Application actor from the shared actor pipeline into a standalone utility class (\Activitypub\Application) and self-contained REST controller.
  • The Application is no longer treated as a "virtual user" with ID -1 flowing through Actors::get_by_id(). It exists only as a JSON-LD document and HTTP signing identity.
  • Remove Actors::APPLICATION_USER_ID constant and all -1 guard clauses from Mailer, Follow handler, CLI, Health Check, Outbox, Stream integration, etc.
  • Add migration to rename keypair option from activitypub_keypair_for_-1 to activitypub_application_keypair, with legacy fallback.
  • Deprecate \Activitypub\Model\Application with _deprecated_class() notice pointing to the new classes.
  • Add dedicated @application rewrite rule so the pretty URL resolves outside the actor routing system.
  • Fix WP_Query parameter (numberposts_per_page) and guard strtotime() against empty post_date_gmt.

Other information:

  • Have you written new tests for your changes, if applicable?

Testing instructions:

  • Verify https://example.com/wp-json/activitypub/1.0/application returns a valid Application actor with publicKey, inbox, outbox, and proper @context.
  • Verify https://example.com/@application redirects/resolves to the Application endpoint.
  • Verify WebFinger for acct:application@example.com returns correct data.
  • On an existing installation, verify the Application keypair is preserved after upgrade (keys should not change).
  • Verify HTTP Signature verification still works for outbound GET requests (e.g., fetching remote actor profiles).
  • Run full PHPUnit suite — all tests should pass.

Changelog entry

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • Patch

Type

  • Changed - for changes in existing functionality

Message

Extract Application from the shared actor pipeline into a standalone utility class.

The Application actor is not a real actor — it cannot be followed,
addressed, or interacted with. It exists only as a JSON-LD document
and a signing identity for outbound HTTP GET requests.

This introduces a standalone `Application` utility class with static
methods for identity (`get_id()`, `get_url()`, `get_webfinger()`) and
key management (`get_key_id()`, `get_public_key()`, `get_private_key()`).

- Remove `APPLICATION_USER_ID` (-1) from `Actors` collection
- Remove Application cases from `user_can_activitypub()`, Follow handler,
  Mailer, Outbox, CLI, Health Check, and Stream connector
- Make `Application_Controller` delegate to the new `Application` class
- Deprecate `Model\Application` (kept for backward compatibility)
- Rename option from `activitypub_keypair_for_-1` to
  `activitypub_application_keypair` with migration
- Add self-contained WebFinger discovery via `webfinger_data` filter,
  handling `acct:`, `/@application`, and REST API URL patterns
- Add missing backslash prefix on \_deprecated_class() call.
- Fix WP_Query parameter from 'number' to 'posts_per_page'.
- Guard strtotime() against false when post_date_gmt is empty.
- Add 'invisible' property to Application REST schema.
- Use pretty URL for Application 'url' field.
- Add @SInCE unreleased tags to new Application class.
- Add comment explaining @Application rewrite rule ordering.
- Remove Application user (ID -1) from Following test.
- Add backslash prefix to wp_cache_flush() in Migration.
- Add backslash prefix to is_string() in Application.
Run the Application WebFinger filter at priority 2 (after
Integration\Webfinger::add_pseudo_user_discovery at priority 1) so
the Application JRD is not overwritten by a WP_Error. Register a
/application/outbox route returning an empty OrderedCollection to
back the URL already advertised in the Application actor document.
- Backslash-prefix `is_string()` calls in Application::generate_key_pair().
- Use `update_option()` instead of `add_option()` to prevent keypair race.
- Use Application::get_webfinger() in health check so it works regardless
  of actor mode or authentication context.
- Add `@since unreleased` to generate_key_pair(), check_legacy_key_pair(),
  and Application_Controller::get_item().
- Add negative test for `acct:application@host` resolving to WP_Error in
  the Actors collection.
- Probe the Application endpoint (GET-readable) instead of the shared
  inbox (POST-only) in is_rest_api_accessible() health check.
- Guard strrchr() return in is_application_resource() to avoid passing
  false to substr() (PHP 8 deprecation).
- Fix migration docblock: clarify that legacy separate key options are
  migrated lazily, not by this function. Add missing @SInCE tag.
…lication-from-actor-system

# Conflicts:
#	includes/class-migration.php
#	includes/class-router.php
#	tests/phpunit/tests/includes/class-test-migration.php
#	tests/phpunit/tests/includes/collection/class-test-following.php
- Restore Actors::APPLICATION_USER_ID as a deprecated back-compat constant
  (class-stats-image.php still references it; removing it caused a fatal).
- Cover the activitypub_keypair_for_-1 option in check_legacy_key_pair() so
  the Application signing key is never regenerated when get_keypair() runs
  before the keypair migration.
- Add changelog entry.
- following: drop the stray $accept_5 block (no $outbox_item_5 setup; left
  over from the trunk merge) that caused an undefined-variable error and phpcs
  warnings.
- feature-request: resolve the Application id via \Activitypub\Application::get_id()
  instead of Actors::get_by_id( -1 ) (which now returns WP_Error → get_id() fatal).
- interaction-policy: declare the expected Model\Application deprecation notice.
- stats-image: resolve the Application webfinger via the new
  \Activitypub\Application::get_webfinger() instead of instantiating the
  deprecated Model\Application (which emitted a deprecation notice).
- application: move class constants to the top of the class.
- migration: drop the orphaned activitypub_keypair_for_-1 row when the
  destination keypair option already exists (early get_keypair() read).
- Reserve the 'application' username in Actors::get_id_by_username() so the
  advertised /@Application handle can't be hijacked by a local user named
  'application' during shared-inbox recipient resolution (the special-case was
  dropped when the Application left the Actors collection).
- Re-apply the activitypub_activity_object_array and
  activitypub_activity_application_object_array filters in the /application
  endpoint so integrations that add actor fields via those hooks still apply.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant