From 647cf0d33d8e7a516976c119fbb9a6da28b555c8 Mon Sep 17 00:00:00 2001 From: Michael Gaffney Date: Sat, 22 Apr 2023 10:47:53 -0400 Subject: [PATCH] feat(sql): Add URL safe base64 encoding function This adds a SQL function to encode binary data into the URL safe base64 encoding defined in RFC 4648. --- .../oss/postgres/80/01_history_domain.up.sql | 19 ++++++++++ internal/db/sqltest/Makefile | 1 + .../history/wt_encode_base64_url_safe.sql | 37 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql create mode 100644 internal/db/sqltest/tests/history/wt_encode_base64_url_safe.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 new file mode 100644 index 0000000000..1e9135f22a --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/80/01_history_domain.up.sql @@ -0,0 +1,19 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + + -- Encodes binary data into URL safe base64 as specified in RFC 4648 Section 5. + -- See https://www.rfc-editor.org/rfc/rfc4648.html#section-5 + create function wt_encode_base64_url_safe(bytes bytea) returns text + as $$ + select rtrim(replace(replace(encode(bytes, 'base64'), '/', '_'), '+', '-'), '='); + $$ language sql + immutable + parallel safe -- all of the functions called are parallel safe + cost 1 -- all of the functions called are cost 1 + strict; -- means the function returns null on null input + comment on function wt_encode_base64_url_safe is + 'Encodes binary data into URL safe base64'; + +commit; diff --git a/internal/db/sqltest/Makefile b/internal/db/sqltest/Makefile index 29b88ae610..92fc43cd1a 100644 --- a/internal/db/sqltest/Makefile +++ b/internal/db/sqltest/Makefile @@ -29,6 +29,7 @@ TESTS ?= tests/setup/*.sql \ tests/hcp/*/*.sql \ tests/kms/*.sql \ tests/plugin/*.sql \ + tests/history/*.sql \ tests/recording/*.sql POSTGRES_DOCKER_IMAGE_BASE ?= postgres diff --git a/internal/db/sqltest/tests/history/wt_encode_base64_url_safe.sql b/internal/db/sqltest/tests/history/wt_encode_base64_url_safe.sql new file mode 100644 index 0000000000..3cdfccf592 --- /dev/null +++ b/internal/db/sqltest/tests/history/wt_encode_base64_url_safe.sql @@ -0,0 +1,37 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + select plan(6); + + -- Verify the function exists and is declared properly + select has_function('wt_encode_base64_url_safe', array['bytea']); + select volatility_is('wt_encode_base64_url_safe', 'immutable'); + select is_strict('wt_encode_base64_url_safe'); + + -- There are 3 differences between regular base64 and URL safe base64: + -- 1. the '_' character is used in place of '/' + -- 2. the '-' character is used in place of '+' + -- 3. trailing '=' characters used for padding are removed + -- + -- See https://www.rfc-editor.org/rfc/rfc4648.html#section-5 + -- + -- We only need to test these three changes since wt_encode_base64_url_safe + -- uses PostgreSQL's native encode function to encode the input into standard + -- base64. + -- + -- The input for this test was found at https://commons.apache.org/proper/commons-codec/xref-test/org/apache/commons/codec/binary/Base64Test.html + -- + -- The regular base64 encoding of the binary data encoded in the hex string '2bf7cc2701fe4397b49ebeed5acc7090' + -- is 'K/fMJwH+Q5e0nr7tWsxwkA==' which contains the '/', '+', and '=' + -- characters, making it the perfect test case. + -- + -- Validate this truely is the perfect test case + select is(encode('\x2bf7cc2701fe4397b49ebeed5acc7090'::bytea, 'base64'), 'K/fMJwH+Q5e0nr7tWsxwkA=='); + -- Now test our function + select is(wt_encode_base64_url_safe('\x2bf7cc2701fe4397b49ebeed5acc7090'::bytea), 'K_fMJwH-Q5e0nr7tWsxwkA'); + -- Verify the 'returns null on null input' is correct + select is(wt_encode_base64_url_safe(null), null); + + select * from finish(); +rollback;