From 327d950a1e7873fc8cd039f76450d09bd2409282 Mon Sep 17 00:00:00 2001 From: Michael Gaffney Date: Mon, 24 Apr 2023 12:10:18 -0400 Subject: [PATCH] feat(sql): Add function to generate a URL safe ID This adds a SQL function that generates a secure random ID of at least 14 characters suitable for use as a public or private ID. IDs generated with the function will only contain characters from the unreserved character set defined in RFC 3986 Section 2.3 making them safe for use in a URL. --- .../oss/postgres/80/01_history_domain.up.sql | 15 ++++++++ .../tests/history/wt_url_safe_id_func.sql | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 internal/db/sqltest/tests/history/wt_url_safe_id_func.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 784941292b..f0baa9e6db 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 @@ -30,4 +30,19 @@ begin; comment on domain wt_url_safe_id is 'An ID that contains only URL safe characters'; + -- wt_url_safe_id is a function that generates a secure random ID of 14 + -- characters suitable for use as a public or private ID. IDs generated with + -- this function will only contain characters from the unreserved character set + -- defined in RFC 3986 Section 2.3 making them safe for use in a URL. + -- See https://www.rfc-editor.org/rfc/rfc3986.html#section-2.3 + create function wt_url_safe_id() returns text + as $$ + select wt_encode_base64_url_safe(gen_random_bytes(10)); + $$ language sql + volatile + parallel safe -- all of the functions called are parallel safe + cost 1; -- all of the functions called are cost 1 + comment on function wt_url_safe_id is + 'Returns a random ID of 14 characters containing URL safe characters only'; + commit; diff --git a/internal/db/sqltest/tests/history/wt_url_safe_id_func.sql b/internal/db/sqltest/tests/history/wt_url_safe_id_func.sql new file mode 100644 index 0000000000..062bcf5488 --- /dev/null +++ b/internal/db/sqltest/tests/history/wt_url_safe_id_func.sql @@ -0,0 +1,34 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + select plan(7); + -- Verify the function exists and is declared properly + select has_function('wt_url_safe_id'); + select volatility_is('wt_url_safe_id', 'volatile'); + select isnt_strict('wt_url_safe_id'); + + create table test_table ( + id wt_url_safe_id default wt_url_safe_id() primary key, + test_num integer not null + ); + + create function test_setup_data(count integer) returns integer + as $$ + begin + for i in 1..count loop + insert into test_table (test_num) values (i); + end loop; + return count; + end; + $$ language plpgsql; + + select is(test_setup_data(100000), 100000); + select is(count(*), 100000::bigint, 'test_table should have 100000 rows') from test_table; + select is(count(*), 0::bigint, 'no id should be longer than 14 characters') + from test_table where length(id) > 14; + select is(count(*), 0::bigint, 'no id should be shorter than 14 characters') + from test_table where length(id) < 14; + + select * from finish(); +rollback;