WebsitePolicy website.policy@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- connect
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/website/policy.v1.json
website.policy@1: how a Share decides who may reach it and under what conditions (public, OpenVibe sign-in, named people or projects, password, one-time link, expiry), plus IP/country rules, rate limits, a bot check, a WAF preset and required device posture. mode is the only field required except that expiry also requires a non-null expires_at. id, owner and version are present when Connect returns a stored policy. Password and one-time policies stay inactive until their credential or link is configured through the CON-5 API. A password is stored as a one-way hash beside this record and is never part of this document; password_set only says one exists.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | string | Present on a stored policy; omitted when the policy is written inline with a new share. |
| |
owner | any | The person who owns the policy; set from the token when a policy is created. | ||
project_id | string | null | The project scope, when the policy belongs to one. |
| |
name | string |
| ||
mode | enum | yes | public: anyone with the link after the abuse screen; signin: any OpenVibe account (optionally a project); named: allowed_subjects/allowed_projects only; password: a shared password; one_time: single-use links; expiry: public access only until expires_at. An expires_at may also cap any other mode. |
|
allowed_subjects | identity.subject-ref | Explicit people or agents allowed in named mode; a project's members are allowed through allowed_projects instead. |
| |
allowed_projects | array of string | Projects whose members may reach a named or signin share. |
| |
ip_allow | array of string | CIDR ranges allowed before any other rule; empty means no IP allowlist. |
| |
ip_deny | array of string | CIDR ranges always refused; evaluated before the allowlist. |
| |
country_allow | array of string | ISO 3166-1 alpha-2 country codes allowed; empty means all. |
| |
country_deny | array of string |
| ||
rate_limits | object |
| ||
rate_limits.per_share_per_minute | integer |
| ||
rate_limits.per_ip_per_minute | integer |
| ||
rate_limits.max_connections | integer |
| ||
rate_limits.max_request_bytes | integer |
| ||
bot_check | enum |
| ||
waf_preset | enum | Defense in depth at the edge; Cloudflare's managed rules run in front of it for HTTP/WS. |
| |
posture_required | array of enum | Self-reported device posture a share may require; a signal, not a guarantee. |
| |
password_set | boolean | Read-only: true when a password hash exists. The hash itself never leaves Connect. | ||
password_hint | string | null | An optional hint shown on the password page; never the password. |
| |
one_time_max_uses | integer | For one_time mode; 1 unless the owner allows more. |
| |
session_ttl_seconds | integer | How long a host-only __Host-ov_session on the share host stays valid after sign-in. |
| |
expires_at | string | null | The absolute end of the policy; required and non-null for expiry mode, optional for other modes. |
| |
version | integer | The signed policy version the edge caches and checks on every request; present on a stored policy. |
| |
created_at | string |
| ||
updated_at | string |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: expiry
{
"id": "pol_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
"owner": {
"type": "user",
"id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
},
"project_id": null,
"name": "Launch demo",
"mode": "expiry",
"allowed_subjects": [],
"allowed_projects": [],
"ip_allow": [],
"ip_deny": [],
"country_allow": [
"DE",
"FR"
],
"country_deny": [],
"rate_limits": {
"per_share_per_minute": 600,
"per_ip_per_minute": 60,
"max_connections": 100,
"max_request_bytes": 10485760
},
"bot_check": "turnstile",
"waf_preset": "standard",
"posture_required": [],
"password_set": false,
"session_ttl_seconds": 3600,
"expires_at": "2026-11-01T00:00:00.000Z",
"version": 3,
"created_at": "2026-10-29T08:00:00.000Z",
"updated_at": "2026-10-29T09:00:00.000Z"
}Valid: password
{
"id": "pol_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
"owner": {
"type": "user",
"id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
},
"project_id": null,
"name": "Password for the demo",
"mode": "password",
"allowed_subjects": [],
"allowed_projects": [],
"ip_allow": [],
"ip_deny": [],
"country_allow": [
"DE",
"FR"
],
"country_deny": [],
"rate_limits": {
"per_share_per_minute": 600,
"per_ip_per_minute": 60,
"max_connections": 100,
"max_request_bytes": 10485760
},
"bot_check": "turnstile",
"waf_preset": "standard",
"posture_required": [],
"password_set": true,
"password_hint": "the one from the call",
"one_time_max_uses": 1,
"session_ttl_seconds": 3600,
"expires_at": null,
"version": 3,
"created_at": "2026-10-29T08:00:00.000Z",
"updated_at": "2026-10-29T09:00:00.000Z"
}Rejected: bad-mode
{
"mode": "invite_only"
}Rejected: missing-expiry
{
"id": "pol_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
"owner": {
"type": "user",
"id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
},
"project_id": null,
"name": "Launch demo",
"mode": "expiry",
"allowed_subjects": [],
"allowed_projects": [],
"ip_allow": [],
"ip_deny": [],
"country_allow": [
"DE",
"FR"
],
"country_deny": [],
"rate_limits": {
"per_share_per_minute": 600,
"per_ip_per_minute": 60,
"max_connections": 100,
"max_request_bytes": 10485760
},
"bot_check": "turnstile",
"waf_preset": "standard",
"posture_required": [],
"password_set": false,
"session_ttl_seconds": 3600,
"version": 3,
"created_at": "2026-10-29T08:00:00.000Z",
"updated_at": "2026-10-29T09:00:00.000Z"
}Rejected: null-expiry
{
"id": "pol_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
"owner": {
"type": "user",
"id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
},
"project_id": null,
"name": "Launch demo",
"mode": "expiry",
"allowed_subjects": [],
"allowed_projects": [],
"ip_allow": [],
"ip_deny": [],
"country_allow": [
"DE",
"FR"
],
"country_deny": [],
"rate_limits": {
"per_share_per_minute": 600,
"per_ip_per_minute": 60,
"max_connections": 100,
"max_request_bytes": 10485760
},
"bot_check": "turnstile",
"waf_preset": "standard",
"posture_required": [],
"password_set": false,
"session_ttl_seconds": 3600,
"expires_at": null,
"version": 3,
"created_at": "2026-10-29T08:00:00.000Z",
"updated_at": "2026-10-29T09:00:00.000Z"
}Rejected: secret-field
{
"mode": "password",
"password_hash": "$argon2id$v=19$m=65536,t=3,p=4$example$example"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('website.policy@1', value); // { valid, errors: [{ path, message }] }