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.
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 80ddb8c5df822e290afdd3c7
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.
policy.json
{
"auth": {
"anonymous": true
},
"constants": {
"AGENT_ADDRESS": "DSn9x7ELmNGm4xiuqMtMiDqY6Cugo9FWsJk9eQGbJ2yg",
"AGENT_ADDRESS_BOUND": true
},
"drops/$dropId": {
"description": "One share: files waiting on the sender's device. Only devices that joined it can read it; the random id is the secret that the link, QR code or 6-digit code hands over. It holds no file names, sizes or contents, only whether sharing is open and the sender's current session (a new one each time the sender's page starts sharing, which tells receivers to connect again).",
"fields": {
"owner": "String!",
"session": "String",
"open": "Bool",
"createdAt": "UInt!"
},
"rules": {
"read": "@user.id != null && get(/drops/$dropId/joins/@user.id) != null",
"create": "@user.id != null && @newData.owner == @user.id && @newData.createdAt <= @time.now && @newData.open == true && @StringUtils.length(@newData.session) <= 40 && getAfter(/drops/$dropId/joins/@user.id) != null",
"update": "@user.id != null && @data.owner == @user.id && @StringUtils.length(@newData.session) <= 40",
"delete": "false"
}
},
"drops/$dropId/joins/$userId": {
"description": "A device in this share: the sender (role sender) or a device that opened the link (role receiver), with a name such as iPhone or Windows computer. Knowing the share's id is enough to join while sharing is open. Only the device itself and the sender can read it.",
"fields": {
"role": "String!",
"name": "String",
"at": "UInt!"
},
"rules": {
"read": "@user.id != null && (@user.id == $userId || get(/drops/$dropId).owner == @user.id)",
"create": "@user.id != null && @user.id == $userId && @newData.at <= @time.now && @StringUtils.length(@newData.name) >= 1 && @StringUtils.length(@newData.name) <= 40 && ((@newData.role == 'receiver' && get(/drops/$dropId) != null && get(/drops/$dropId).open == true) || (@newData.role == 'sender' && get(/drops/$dropId) == null && getAfter(/drops/$dropId).owner == @user.id))",
"update": "false",
"delete": "@user.id != null && (@user.id == $userId || get(/drops/$dropId).owner == @user.id)"
}
},
"drops/$dropId/links/$receiverId": {
"description": "Connection setup between one receiving device and the sender (WebRTC signaling): the receiver's offer and the sender's answer, each a session description that lists the network addresses to try. File names and contents never pass through here; they go device to device. Overwritten on every connection attempt and deleted by the sender when sharing stops. A receiver can only ask to connect while sharing is open.",
"fields": {
"offer": "String",
"offerId": "String",
"session": "String",
"answer": "String",
"answerId": "String",
"at": "UInt"
},
"rules": {
"read": "@user.id != null && (@user.id == $receiverId || get(/drops/$dropId).owner == @user.id) && get(/drops/$dropId/joins/$receiverId) != null",
"create": "@user.id != null && @user.id == $receiverId && get(/drops/$dropId/joins/@user.id) != null && get(/drops/$dropId).open == true && @newData.at <= @time.now && @StringUtils.length(@newData.offer) <= 20000 && @StringUtils.length(@newData.offerId) <= 40 && @StringUtils.length(@newData.session) <= 40 && @newData.answer == '' && @newData.answerId == ''",
"update": "@user.id != null && get(/drops/$dropId/joins/$receiverId) != null && ((@user.id == $receiverId && get(/drops/$dropId).open == true && @newData.at <= @time.now && @StringUtils.length(@newData.offer) <= 20000 && @StringUtils.length(@newData.offerId) <= 40 && @StringUtils.length(@newData.session) <= 40 && @newData.answer == '' && @newData.answerId == '') || (get(/drops/$dropId).owner == @user.id && @newData.offer == @data.offer && @newData.offerId == @data.offerId && @newData.session == @data.session && @newData.at == @data.at && @newData.answerId == @data.offerId && @StringUtils.length(@newData.answer) <= 20000))",
"delete": "@user.id != null && (@user.id == $receiverId || get(/drops/$dropId).owner == @user.id)"
}
},
"codes/$code": {
"description": "A 6-digit code shown on the sending device. It points to the share for 10 minutes. Reading one needs a try (codetries) recorded since the code was written, so an old try does not open a later share that gets the same code, and tries are rate limited, so the million possible codes cannot be scanned. The sender replaces its code every 10 minutes while sharing and deletes it when sharing stops; an expired code can be taken by another sender.",
"fields": {
"drop": "String",
"by": "String",
"at": "UInt"
},
"rules": {
"read": "@user.id != null && get(/codetries/@user.id/t/$code) != null && get(/codetries/@user.id/t/$code).at >= @data.at && @data.at + 600 >= @time.now",
"create": "@user.id != null && @newData.by == @user.id && @newData.at <= @time.now && @StringUtils.length(@newData.drop) == 20",
"update": "@user.id != null && (@data.by == @user.id || @data.at + 600 < @time.now) && @newData.by == @user.id && @newData.at <= @time.now && @StringUtils.length(@newData.drop) == 20",
"delete": "@user.id != null && @data.by == @user.id"
}
},
"codetries/$userId/t/$code": {
"description": "One device trying one 6-digit code, and when (server time). Each device may try 10 codes in 10 minutes, and all devices together 1,000.",
"tier": "durable",
"fields": {
"n": "UInt",
"at": "UInt"
},
"rules": {
"read": "@user.id != null && @user.id == $userId",
"create": "@user.id != null && @user.id == $userId && @newData.n == 1 && @newData.at <= @time.now",
"update": "false",
"delete": "false"
},
"invariants": [
{
"type": "rollingSum",
"name": "code_tries_per_device",
"field": "n",
"windowSeconds": 600,
"limit": 10,
"scopeVariable": "$userId"
},
{
"type": "rollingSum",
"name": "code_tries_everyone",
"field": "n",
"windowSeconds": 600,
"limit": 1000
}
]
}
}
Change history
Point OpenApps links to openapps.free
Bind agent address in policy
Retry release capture
Use OpenApps service URLs and add contribution strip
Bounded source sync
Bounded source sync
Bounded source sync