Skip to content

Shorten a viewer map URL the caller can open #272

Closed

Description

@fjlopez

The viewer asks the backend to shorten the map URL it is about to share. The browser does not call tinyurl.com.

The caller sends the map URL. It sends the HttpOnly viewer_access_token cookie when the browser has one.

No cookie. The anonymous filter principal is public. That is the public visitor. publicAuthClearGuard clears viewer_access_token on /public/**, so a public map has no cookie. Allow the request when that principal can open the application and territory in the URL. The gate is the same one as GET /api/config/client/profile/{appId}/{terrId}: findApplicationByUserApplicationAndTerritory for username public. mayAccessApplication only rejects a private application. It does not check the territory. No matching pair returns 403, with the same problem response the profile endpoint returns.

The built-in public user has no password and does not receive viewer_access_token. The public visitor is the request with no cookie. A cookie that identifies a registered user is allowed when that user can open the same application and territory. A cookie that does not identify a registered user returns 401. The admin cookie and a mobile Bearer token are this case. A missing cookie is not.

Provider

The endpoint does not branch on the provider name. It resolves the caller, refuses a URL that is not this deployment's viewer map, refuses a map the caller cannot open, then calls the selected ShortUrlProvider. A later definitive provider is a new implementation and a new config value. The endpoint stays as it is.

sitmun:
  short-url:
    provider: none
    tinyurl-legacy:
      endpoint: https://tinyurl.com/api-create.php

sitmun.short-url.provider is the id. Shipped ids are none and tinyurl-legacy. The default is none. Each provider is a Spring bean with that id. Startup indexes the beans by id and fails when the configured id is missing or when two beans share an id. A missing property is none.

none is a provider. It returns the submitted URL and calls no host. It is not a null check in the endpoint.

tinyurl-legacy reads only sitmun.short-url.tinyurl-legacy. It POSTs the map URL to that endpoint, which defaults to https://tinyurl.com/api-create.php.

A definitive provider adds its own id, its own bean, and its own sitmun.short-url.<id> block for a token or base URL. It does not read the TinyURL block. The viewer still receives a URL or an error and does not learn the provider id.

Each provider returns one of three results.

  • Original. The submitted URL. Only none returns this.
  • Shortened. A different URL.
  • Failed. A message. The endpoint does not replace that with the original URL.

The map-URL check runs before shorten(), so every provider, including a future one, refuses the same foreign destinations.

Responses

  • Original. 200 and the URL the caller sent.
  • Shortened. 200 and the short URL.
  • The caller cannot open that application and territory. 403, the same problem response as the profile.
  • A cookie is present and it does not identify the public user or a registered user. 401.
  • Failed, or a URL that is not this viewer map. An error response with a message.

Legacy TinyURL

Checked on 2026-10-04.

  • A server POST to https://tinyurl.com/api-create.php with no account returned HTTP 200 and https://tinyurl.com/22wyblfp. access-control-allow-origin was https://tinyurl.com only, which is why the viewer page cannot read it.
  • POST https://api.tinyurl.com/create with no token returned HTTP 401 Unauthenticated.
  • TinyURL's own posts say http://tinyurl.com/api-create.php was never officially supported and is deprecated. Links created with it show an interstitial before the destination. TinyURL cannot attach those links to an account, edit them, or delete them. No end date is set. Sources: Retiring Our Old API Endpoint and Why Does My TinyURL Link Show an Ad or Preview Screen.
  • The pricing page the same day lists a free plan at 30 links a month and Pro at $9 a month for 125 links. The documented API still requires a bearer token. This issue does not call that API.

tinyurl-legacy is the first provider that calls a shortener. A server POST still returns a short URL with no account. TinyURL does not support that endpoint. The definitive provider replaces it by config. Until an operator sets tinyurl-legacy, the default none returns the original map URL.

Acceptance

  • No cookie, when the public user can open the application and territory in the URL, is allowed. sitmun.short-url.provider=none returns the submitted map URL and does not call a shortener.
  • No cookie, and the public user cannot open that pair, returns 403.
  • A valid registered viewer cookie is allowed when that user can open the pair, and returns 403 when they cannot.
  • A cookie that does not identify a registered user returns 401.
  • A caller who can open the pair, with sitmun.short-url.provider=tinyurl-legacy, receives the short URL from api-create.php. The browser never sees that host.
  • A missing property behaves as none.
  • A failed provider call returns an error message and does not return the original URL.
  • A URL that is not this viewer map returns an error before any provider runs.
  • Adding a provider does not add a branch to the endpoint. It adds one ShortUrlProvider bean, one id, and that provider's own config block.
  • The admin cookie and a Bearer mobile token do not authorize this route.

Parent: sitmun/sitmun-viewer-app#189

Activity

  1. added
    enhancementNew feature or request
    plannedActive backlog; exempt from stale bot
    on Oct 4, 2026
  2. added theissue type on Oct 4, 2026
  3. changed the title [-]Shorten a viewer map URL for an identified session[/-] [+]Shorten a viewer map URL the caller can open[/+] on Oct 4, 2026
  4. fjlopez commented on Oct 4, 2026

    @fjlopez
    ContributorAuthor

    Corrected the no-cookie rule.

    A missing viewer_access_token is the anonymous principal public, not a 401. Allow it when that principal can open the application and territory in the URL. The gate is findApplicationByUserApplicationAndTerritory, the same one as GET /api/config/client/profile/{appId}/{terrId}. mayAccessApplication only rejects a private application and does not check the territory. No pair is 403. 401 stays for a cookie that does not identify the built-in public user or a registered user, including the admin cookie and a mobile Bearer token.

  5. fjlopez commented on Oct 4, 2026

    @fjlopez
    ContributorAuthor

    The built-in public user does not receive viewer_access_token. Login keeps that password null, and ROLE_PUBLIC exists only on the anonymous filter. The public visitor is the request with no cookie. A viewer cookie is a registered user.

  6. fjlopez commented on Oct 4, 2026

    @fjlopez
    ContributorAuthor

    Verified POST /api/config/client/short-url with no cookie.

    • http://localhost:9000/viewer/public/map/12/4?mapState=abc returns 200 and the same URL (sitmun.short-url.provider is none).
    • https://evil.example/viewer/public/map/12/4 returns 400 URL is not a viewer map. The provider is not called.
    • http://localhost:9000/viewer/public/map/99999/99999 returns 403.

    The TinyURL provider uses OkHttp. The default provider does not call TinyURL.

  7. fjlopez commented on Oct 4, 2026

    @fjlopez
    ContributorAuthor

    Landed on dev with sitmun/sitmun-application-stack#81.

    A public map on http://localhost:4200/public/map/12/4 shortened through POST /api/config/client/short-url. The request went to http://localhost:9000/backend/api/config/client/short-url and the response kept the same map URL. The default provider is none.

    Shorten posts to the backend

  8. fjlopez commented on Oct 4, 2026

    @fjlopez
    ContributorAuthor

    The caller can shorten a viewer map URL they can open.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestplannedActive backlog; exempt from stale bot

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions