tools

Small tools for the command line

Push notifications, locks and QR codes.

Base URL https://tools.worotyns.ovh

Push

Web push notifications from curl.

Locks

Named lock flags for cron jobs, CI and shell scripts.

QR

QR code images for any text or URL, on the fly.

Push

Open push setup

Notifications arrive in the browser that subscribed, even when the tab is closed. The subscription id is the only secret needed to send to it.

Get a subscription

  1. Open the push page in the browser or device that should receive notifications.
  2. Allow notifications. A service worker is registered and the browser is subscribed.
  3. Copy the subscription id and one of the curl commands shown there.

Send a notification

curl -X POST https://tools.worotyns.ovh/push/send \
  -H "content-type: application/json" \
  -d '{"subscription": "SUBSCRIPTION_ID", "title": "Service is down", "message": "Check servers", "url": "https://example.com"}'

Plain text is simpler: the request body becomes the message. title and url are optional query parameters.

curl -d "Backup finished" "https://tools.worotyns.ovh/push/send/SUBSCRIPTION_ID?title=NAS&url=https://nas.local"

# GET works too, for simple webhooks
curl "https://tools.worotyns.ovh/push/send/SUBSCRIPTION_ID?message=Done&title=Build"

# with an icon
curl -d "Backup finished" "https://tools.worotyns.ovh/push/send/SUBSCRIPTION_ID?title=NAS&icon=https%3A%2F%2Fexample.com%2Ficon.png"

Optional fields

FieldWhereMeaning
urlJSON, ?url=Opened when the notification is clicked.
iconJSON, ?icon=Small icon next to the text; HTTPS URL or same-origin path.
badgeJSON, ?badge=Monochrome icon for the Android status bar.
imageJSON, ?image=Large image below the text (Chrome, Android).

Icons must be reachable over HTTPS from the device. Without icon, the tools icon is used.

API

MethodPathPurpose
GET/push/vapidPublic VAPID key as JSON.
POST/push/subscriptionRegister a browser PushSubscription; returns {"success":true,"subscription":"ID"}.
GET/push/subscriptionFind an id by ?endpoint=....
POST/push/subscription/changeRotate the endpoint, keeping the id.
DELETE/push/subscriptionRemove by {"endpoint":"..."}.
POST/push/sendSend a JSON notification.
POST and GET/push/send/{id}Send a text notification.

Status codes

CodeMeaning
200Sent.
404Unknown subscription.
410Subscription expired; it is deleted automatically.
413Message too large (plaintext max ~3000 bytes).
502The push service rejected the message.

The browser UI lives under /push/, so its service worker scope is /push/. Subscription rotation is handled by web/push/sw.js, so ids survive browser restarts. Push requires HTTPS.

Locks

A lock is a named flag stored on the server. Reading it returns 204 when unlocked and 423 when locked, so curl -f can drive shell logic directly.

Create a lock

curl -X POST "https://tools.worotyns.ovh/locks?l=1&e=60&k=my-secret-key"
{ "lockId": "01j...", "lockKey": "my-secret-key" }
ParameterRequiredMeaning
lnoIf present, create the lock already locked.
enoTTL in seconds for the initial locked state.
knoCustom key; otherwise a random one is returned.

Keep lockId and lockKey: the id identifies the lock, the key authorises changes.

Check the state

curl -f "https://tools.worotyns.ovh/locks/LOCK_ID" && echo "not locked"
CodeMeaning
204Unlocked.
423Locked.
404Unknown lock.

Lock and unlock

curl -X PATCH "https://tools.worotyns.ovh/locks/LOCK_ID/lock?k=LOCK_KEY&e=60"
curl -X PATCH "https://tools.worotyns.ovh/locks/LOCK_ID/unlock?k=LOCK_KEY"

e is optional; without it the lock stays locked until explicitly unlocked. Responses: 204 ok, 401 bad key, 404 unknown lock.

Use it in a script

# run only when nobody holds the lock
curl -fsS "https://tools.worotyns.ovh/locks/LOCK_ID" >/dev/null || exit 0
./deploy.sh

QR

Returns a QR code for arbitrary data. Useful for links on a dashboard, WiFi strings, or anything a phone should scan.

curl "https://tools.worotyns.ovh/qr?data=https%3A%2F%2Fexample.com" -o qr.png

# SVG or GIF, custom size
curl "https://tools.worotyns.ovh/qr?data=hello&size=512&format=svg" -o qr.svg
ParameterRequiredMeaning
datayesThe text or URL to encode.
sizenoImage width in pixels, 64–1024. Default 256.
formatnopng (default), svg or gif.
pknoShared key, required only when QR_KEY is configured.

Embed it directly in HTML:

<img src="https://tools.worotyns.ovh/qr?data=https%3A%2F%2Fexample.com" alt="QR code">

Missing data returns 400, a bad or missing key returns 401. Responses are stateless and cached for a day.

No pk is required on this instance. Set QR_KEY to require one.