links-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 9e2af813edac
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 3151231032497ed786b88a0a
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
policy.json
{
  "constants": {
    "AGENT_ADDRESS": "24gmeEA1NV8yX3knGjjWZ5RAPp3quE9nnNCwE2vmfhaG",
    "AGENT_ADDRESS_BOUND": true
  },
  "auth": {
    "anonymous": true
  },
  "links/$code": {
    "description": "A short link: /<code> opens url. Readable only by its owners and by the public api function (which resolves redirects and counts clicks), so nobody can list codes or read destinations.",
    "fields": {
      "url": "String",
      "createdBy": "String!",
      "createdAt": "UInt!",
      "clicks": "UInt",
      "disabled": "Bool"
    },
    "rules": {
      "read": "@user.id != null && (@user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API || get(/links/$code/owners/@user.id) != null)",
      "create": "@user.id != null && get(/links/$code) == null && @newData.createdBy == @user.id && @newData.createdAt <= @time.now && @newData.clicks == 0 && @newData.disabled == false && @StringUtils.length($code) >= 3 && @StringUtils.length($code) <= 32 && @StringUtils.length(@newData.url) >= 10 && @StringUtils.length(@newData.url) <= 2000 && getAfter(/links/$code/owners/@user.id) != null && getAfter(/linkkeys/$code) != null",
      "update": "@user.id != null && ((get(/links/$code/owners/@user.id) != null && @newData.clicks == @data.clicks && @StringUtils.length(@newData.url) >= 10 && @StringUtils.length(@newData.url) <= 2000) || (@user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API && @newData.clicks == @data.clicks + 1 && @newData.url == @data.url && @newData.disabled == @data.disabled))",
      "delete": "false"
    }
  },
  "links/$code/owners/$userId": {
    "description": "Someone who may edit the link: its creator, or anyone who presented the link's owner key (the edit link).",
    "fields": {
      "at": "UInt!"
    },
    "rules": {
      "read": "@user.id != null && (@user.id == $userId || @user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API)",
      "create": "@user.id != null && @user.id == $userId && @newData.at <= @time.now && ((get(/links/$code) == null && getAfter(/links/$code).createdBy == @user.id) || (get(/links/$code) != null && getAfter(/linkclaims/$code/c/@user.id).key == get(/linkkeys/$code).key))",
      "update": "false",
      "delete": "false"
    }
  },
  "links/$code/days/$day": {
    "description": "How often a link was opened on one UTC day ($day and d are yyyymmdd). Readable by the link's owners; only the api function writes it, one click at a time.",
    "fields": {
      "d": "UInt",
      "clicks": "UInt"
    },
    "rules": {
      "read": "@user.id != null && (@user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API || get(/links/$code/owners/@user.id) != null)",
      "create": "@user.id != null && @user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API && get(/links/$code) != null && @StringUtils.length($day) == 8 && $day * 1 == @newData.d && @newData.clicks == 1",
      "update": "@user.id != null && @user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API && @newData.d == @data.d && @newData.clicks == @data.clicks + 1",
      "delete": "false"
    }
  },
  "linkkeys/$code": {
    "description": "The link's owner key. Only the api function can read it, to check keys; owners carry it in their edit link.",
    "fields": {
      "key": "String!"
    },
    "rules": {
      "read": "@user.id == @const.BOUNDED_PUBLIC_PRINCIPAL_API",
      "create": "@user.id != null && get(/links/$code) == null && getAfter(/links/$code).createdBy == @user.id && @StringUtils.length(@newData.key) >= 20",
      "update": "false",
      "delete": "false"
    }
  },
  "linkclaims/$code/c/$userId": {
    "description": "A key someone presents to become an owner. Never readable.",
    "fields": {
      "key": "String"
    },
    "rules": {
      "read": "false",
      "create": "@user.id != null && @user.id == $userId",
      "update": "@user.id != null && @user.id == $userId",
      "delete": "false"
    }
  },
  "functions": {
    "api": {
      "auth": "true",
      "entry": "functions/api.ts",
      "public": true,
      "methods": [
        "GET",
        "POST",
        "PATCH"
      ],
      "cors": "passthrough"
    }
  }
}

Change history

Quality pass: clicks per day, CSV export, links on other devices
9e2af813ed · 5 hours ago
Bounded source sync
29eee7dafa · 1 day ago
Bounded source sync
c5e634046a · 1 day ago
Bounded source sync
12abf93e7e · 1 day ago
Bounded source sync
d0d6a654b1 · 1 day ago
Bounded source sync
e03049f905 · 1 day ago
Bounded source sync
eb5c793bfa · 1 day ago
Bounded source sync
5dd8ec26e1 · 1 day ago