-- The web sites Caddy serves (vpnrouter_sites), in the vpn-router-sites database. -- The whole file runs as one transaction, serialized by an advisory lock, so that two processes can load it at once. SELECT pg_advisory_xact_lock(hashtext('vpn-router sites schema')); -- A static web site: its host names, port, interfaces and TLS, the group whose members change its files, and its -- DNS: user, the router serves no records of its host names, or router, its name server serves A or AAAA records of -- them with the router's public, internal or external address (dns_address). CREATE TABLE IF NOT EXISTS sites ( name text PRIMARY KEY, enabled boolean NOT NULL, hosts text[] NOT NULL, port integer NOT NULL, listen text NOT NULL CHECK (listen IN ('internal', 'external', 'both')), tls text NOT NULL CHECK (tls IN ('none', 'acme', 'ca', 'file')), ca text NOT NULL, certificate text NOT NULL, private_key text NOT NULL, index_file text NOT NULL, spa boolean NOT NULL, editors text NOT NULL, modified timestamptz NOT NULL ); ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns text NOT NULL DEFAULT 'user' CHECK (dns IN ('user', 'router')); ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_address text NOT NULL DEFAULT 'public' CHECK (dns_address IN ('public', 'internal', 'external')); -- The functions whose columns and the procedure whose arguments changed with dns and dns_address. DROP FUNCTION IF EXISTS sites_list(); DROP FUNCTION IF EXISTS site_get(text); DROP FUNCTION IF EXISTS sites_served(); DROP PROCEDURE IF EXISTS site_put(text, boolean, text[], integer, text, text, text, text, text, text, boolean, text); -- Every site, by name; the private key is left out. CREATE OR REPLACE FUNCTION sites_list() RETURNS TABLE (name text, enabled boolean, hosts text[], port integer, listen text, tls text, ca text, certificate text, index_file text, spa boolean, editors text, dns text, dns_address text, modified timestamptz) LANGUAGE sql STABLE AS $$ SELECT name, enabled, hosts, port, listen, tls, ca, certificate, index_file, spa, editors, dns, dns_address, modified FROM sites ORDER BY name; $$; -- The site with its private key. CREATE OR REPLACE FUNCTION site_get(p_name text) RETURNS TABLE (name text, enabled boolean, hosts text[], port integer, listen text, tls text, ca text, certificate text, private_key text, index_file text, spa boolean, editors text, dns text, dns_address text, modified timestamptz) LANGUAGE sql STABLE AS $$ SELECT name, enabled, hosts, port, listen, tls, ca, certificate, private_key, index_file, spa, editors, dns, dns_address, modified FROM sites WHERE name = p_name; $$; -- The enabled sites with their private keys, by name, for Caddy's configuration and certificate files. CREATE OR REPLACE FUNCTION sites_served() RETURNS TABLE (name text, enabled boolean, hosts text[], port integer, listen text, tls text, ca text, certificate text, private_key text, index_file text, spa boolean, editors text, dns text, dns_address text, modified timestamptz) LANGUAGE sql STABLE AS $$ SELECT name, enabled, hosts, port, listen, tls, ca, certificate, private_key, index_file, spa, editors, dns, dns_address, modified FROM sites WHERE enabled ORDER BY name; $$; -- Add the site, or replace all its settings. CREATE OR REPLACE PROCEDURE site_put(p_name text, p_enabled boolean, p_hosts text[], p_port integer, p_listen text, p_tls text, p_ca text, p_certificate text, p_private_key text, p_index_file text, p_spa boolean, p_editors text, p_dns text, p_dns_address text) LANGUAGE sql AS $$ INSERT INTO sites (name, enabled, hosts, port, listen, tls, ca, certificate, private_key, index_file, spa, editors, dns, dns_address, modified) VALUES (p_name, p_enabled, p_hosts, p_port, p_listen, p_tls, p_ca, p_certificate, p_private_key, p_index_file, p_spa, p_editors, p_dns, p_dns_address, now()) ON CONFLICT (name) DO UPDATE SET enabled = p_enabled, hosts = p_hosts, port = p_port, listen = p_listen, tls = p_tls, ca = p_ca, certificate = p_certificate, private_key = p_private_key, index_file = p_index_file, spa = p_spa, editors = p_editors, dns = p_dns, dns_address = p_dns_address, modified = now(); $$; CREATE OR REPLACE PROCEDURE site_remove(p_name text) LANGUAGE sql AS $$ DELETE FROM sites WHERE name = p_name; $$; -- The names of the sites whose files the members of the groups may change. CREATE OR REPLACE FUNCTION sites_editable(p_groups text[]) RETURNS TABLE (name text) LANGUAGE sql STABLE AS $$ SELECT name FROM sites WHERE editors <> '' AND editors = ANY (p_groups) ORDER BY name; $$; -- The names of the sites whose editors are the group. CREATE OR REPLACE FUNCTION sites_of_group(p_group text) RETURNS TABLE (name text) LANGUAGE sql STABLE AS $$ SELECT name FROM sites WHERE editors = p_group ORDER BY name; $$; -- Give the sites of a renamed group its new name. CREATE OR REPLACE PROCEDURE sites_rename_group(p_old text, p_new text) LANGUAGE sql AS $$ UPDATE sites SET editors = p_new, modified = now() WHERE editors = p_old; $$;