From 94f77d36b30cd656456fba7017f9218b97b1197f Mon Sep 17 00:00:00 2001 From: Michael Gaffney Date: Sat, 22 Apr 2023 14:03:34 -0400 Subject: [PATCH] feat(sql): Add a domain type for URL safe IDs This creates a new domain in SQL that constrains the characters of an ID to the unreserved character set defined RFC 3986 Section 2.3. --- .../oss/postgres/80/01_history_domain.up.sql | 14 ++++++ .../tests/history/wt_url_safe_id_domain.sql | 48 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 internal/db/sqltest/tests/history/wt_url_safe_id_domain.sql diff --git a/internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql b/internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql index 1e9135f22a..784941292b 100644 --- a/internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql +++ b/internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql @@ -16,4 +16,18 @@ begin; comment on function wt_encode_base64_url_safe is 'Encodes binary data into URL safe base64'; + -- wt_url_safe_id is a domain that constrains the characters of a value to the + -- unreserved character set defined RFC 3986 Section 2.3. The valid characters are + -- the ASCII characters in the 'a-z', 'A-Z', or '0-9' ranges plus the four ASCII + -- characters '~', '-', '.', and '_'. + -- + -- See https://www.rfc-editor.org/rfc/rfc3986.html#section-2.3 + create domain wt_url_safe_id as text + constraint wt_url_safe_id_can_only_contain_unreserved_characters + check (value ~ '^[a-zA-Z0-9\-~\._]+$') + constraint wt_url_safe_id_must_be_more_than_10_characters + check (length(trim(value)) > 10); + comment on domain wt_url_safe_id is + 'An ID that contains only URL safe characters'; + commit; diff --git a/internal/db/sqltest/tests/history/wt_url_safe_id_domain.sql b/internal/db/sqltest/tests/history/wt_url_safe_id_domain.sql new file mode 100644 index 0000000000..64e98d1cfa --- /dev/null +++ b/internal/db/sqltest/tests/history/wt_url_safe_id_domain.sql @@ -0,0 +1,48 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + select plan(10); + + select has_domain('wt_url_safe_id'); + select domain_type_is('wt_url_safe_id', 'text'); + + create table test_table ( + id wt_url_safe_id primary key + ); + + prepare insert_valid_ids as + insert into test_table + values ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~-._'), + ('__________a'), ('__________1'), ('__________~'), ('__________-'), ('__________.'), ('___________'); + + select lives_ok('insert_valid_ids', 'Inserting IDs with valid characters should not cause an error'); + + prepare insert_slash as insert into test_table values ('/0123456789'); + select throws_like('insert_slash', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Inserting an ID with the "/" character should cause an error'); + + prepare insert_plus as insert into test_table values ('+0123456789'); + select throws_like('insert_plus', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Inserting an ID with the "+" character should cause an error'); + + prepare insert_equals as insert into test_table values ('=0123456789'); + select throws_like('insert_equals', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Inserting an ID with the "=" character should cause an error'); + + prepare insert_percent as insert into test_table values ('%0123456789'); + select throws_like('insert_percent', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Inserting an ID with the "%" character should cause an error'); + + prepare insert_empty as insert into test_table values (' '); + select throws_like('insert_empty', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Inserting an empty ID should cause an error'); + + prepare update_to_invalid as + update test_table + set id = '/0123456789' + where id = '__________a'; + select throws_like('update_to_invalid', '%"wt_url_safe_id_can_only_contain_unreserved_characters"', 'Changing an ID to an invalid character should cause an error'); + + prepare update_to_valid as + update test_table + set id = '0123456789a' + where id = '__________a'; + select lives_ok('update_to_valid', 'Changing an ID to another valid ID should not cause an error'); + select * from finish(); +rollback;