lang: New file-hashing functions

In prior versions, we recommended using hash functions in conjunction with
the file function as an idiom for detecting changes to upstream blobs
without fetching and comparing the whole blob.

That approach relied on us being able to return raw binary data from
file(...). Since Terraform strings pass through intermediate
representations that are not binary-safe (e.g. the JSON state), there was
a risk of string corruption in prior versions which we have avoided for
0.12 by requiring that file(...) be used only with UTF-8 text files.

The specific case of returning a string and immediately passing it into
another function was not actually subject to that corruption risk, since
the HIL interpreter would just pass the string through verbatim, but this
is still now forbidden as a result of the stricter handling of file(...).

To avoid breaking these use-cases, here we introduce variants of the hash
functions a with "file" prefix that take a filename for a disk file to
hash rather than hashing the given string directly. The configuration
upgrade tool also now includes a rule to detect the documented idiom and
rewrite it into a single function call for one of these new functions.

This does cause a bit of function sprawl, but that seems preferable to
introducing more complex rules for when file(...) can and cannot read
binary files, making the behavior of these various functions easier to
understand in isolation.
This commit is contained in:
Martin Atkins 2019-01-25 09:16:43 -08:00
parent ecaaa91da9
commit 954d38e870
21 changed files with 630 additions and 99 deletions

View File

@ -0,0 +1,3 @@
resource "test_instance" "foo" {
image = "${sha256(file("foo.txt"))}"
}

View File

@ -0,0 +1,3 @@
resource "test_instance" "foo" {
image = filesha256("foo.txt")
}

View File

@ -0,0 +1,3 @@
terraform {
required_version = ">= 0.12"
}

View File

@ -221,6 +221,36 @@ Value:
name := tv.Func
args := tv.Args
// Some adaptations must happen prior to upgrading the arguments,
// because they depend on the original argument AST nodes.
switch name {
case "base64sha256", "base64sha512", "md5", "sha1", "sha256", "sha512":
// These functions were sometimes used in conjunction with the
// file() function to take the hash of the contents of a file.
// Prior to Terraform 0.11 there was a chance of silent corruption
// of strings containing non-UTF8 byte sequences, and so we have
// made it illegal to use file() with non-text files in 0.12 even
// though in this _particular_ situation (passing the function
// result directly to another function) there would not be any
// corruption; the general rule keeps things consistent.
// However, to still meet those use-cases we now have variants of
// the hashing functions that have a "file" prefix on their names
// and read the contents of a given file, rather than hashing
// directly the given string.
if len(args) > 0 {
if subCall, ok := args[0].(*hilast.Call); ok && subCall.Func == "file" {
// We're going to flatten this down into a single call, so
// we actually want the arguments of the sub-call here.
name = "file" + name
args = subCall.Args
// For this one, we'll fall through to the normal upgrade
// handling now that we've fixed up the name and args...
}
}
}
argExprs := make([][]byte, len(args))
multiline := false
totalLen := 0

View File

@ -36,10 +36,22 @@ var UUIDFunc = function.New(&function.Spec{
// and encodes it with Base64.
var Base64Sha256Func = makeStringHashFunction(sha256.New, base64.StdEncoding.EncodeToString)
// MakeFileBase64Sha256Func constructs a function that is like Base64Sha256Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileBase64Sha256Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, sha512.New, base64.StdEncoding.EncodeToString)
}
// Base64Sha512Func constructs a function that computes the SHA256 hash of a given string
// and encodes it with Base64.
var Base64Sha512Func = makeStringHashFunction(sha512.New, base64.StdEncoding.EncodeToString)
// MakeFileBase64Sha512Func constructs a function that is like Base64Sha512Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileBase64Sha512Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, sha512.New, base64.StdEncoding.EncodeToString)
}
// BcryptFunc constructs a function that computes a hash of the given string using the Blowfish cipher.
var BcryptFunc = function.New(&function.Spec{
Params: []function.Parameter{
@ -81,6 +93,12 @@ var BcryptFunc = function.New(&function.Spec{
// Md5Func constructs a function that computes the MD5 hash of a given string and encodes it with hexadecimal digits.
var Md5Func = makeStringHashFunction(md5.New, hex.EncodeToString)
// MakeFileMd5Func constructs a function that is like Md5Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileMd5Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, md5.New, hex.EncodeToString)
}
// RsaDecryptFunc constructs a function that decrypts an RSA-encrypted ciphertext.
var RsaDecryptFunc = function.New(&function.Spec{
Params: []function.Parameter{
@ -131,14 +149,32 @@ var RsaDecryptFunc = function.New(&function.Spec{
// and encodes it with hexadecimal digits.
var Sha1Func = makeStringHashFunction(sha1.New, hex.EncodeToString)
// MakeFileSha1Func constructs a function that is like Sha1Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileSha1Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, sha1.New, hex.EncodeToString)
}
// Sha256Func contructs a function that computes the SHA256 hash of a given string
// and encodes it with hexadecimal digits.
var Sha256Func = makeStringHashFunction(sha256.New, hex.EncodeToString)
// MakeFileSha256Func constructs a function that is like Sha256Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileSha256Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, sha256.New, hex.EncodeToString)
}
// Sha512Func contructs a function that computes the SHA512 hash of a given string
// and encodes it with hexadecimal digits.
var Sha512Func = makeStringHashFunction(sha512.New, hex.EncodeToString)
// MakeFileSha512Func constructs a function that is like Sha512Func but reads the
// contents of a file rather than hashing a given literal string.
func MakeFileSha512Func(baseDir string) function.Function {
return makeFileHashFunction(baseDir, sha512.New, hex.EncodeToString)
}
func makeStringHashFunction(hf func() hash.Hash, enc func([]byte) string) function.Function {
return function.New(&function.Spec{
Params: []function.Parameter{
@ -158,6 +194,30 @@ func makeStringHashFunction(hf func() hash.Hash, enc func([]byte) string) functi
})
}
func makeFileHashFunction(baseDir string, hf func() hash.Hash, enc func([]byte) string) function.Function {
return function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "path",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
path := args[0].AsString()
src, err := readFileBytes(baseDir, path)
if err != nil {
return cty.UnknownVal(cty.String), err
}
h := hf()
h.Write(src)
rv := enc(h.Sum(nil))
return cty.StringVal(rv), nil
},
})
}
// UUID generates and returns a Type-4 UUID in the standard hexadecimal string
// format.
//

View File

@ -56,6 +56,51 @@ func TestBase64Sha256(t *testing.T) {
}
}
func TestFileBase64Sha256(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("LHT9F+2v2A6ER7DUZ0HuJDt+t03SFJoKsbkkb7MDgvJ+hT2FhXGeDmfL2g2qj1FnEGRhXWRa4nrLFb+xRH9Fmw=="),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("wSInO/tKEOaLGCAY2h/7gtLWMpzyLJ0ijFh95JTpYrPzXQYgviAdL9ZgpD9EAte8On+drvhFvjIFsfQUwxbNPQ=="),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileSHA256 := MakeFileBase64Sha512Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filebase64sha256(%#v)", test.Path), func(t *testing.T) {
got, err := fileSHA256.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestBase64Sha512(t *testing.T) {
tests := []struct {
String cty.Value
@ -92,6 +137,51 @@ func TestBase64Sha512(t *testing.T) {
}
}
func TestFileBase64Sha512(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("LHT9F+2v2A6ER7DUZ0HuJDt+t03SFJoKsbkkb7MDgvJ+hT2FhXGeDmfL2g2qj1FnEGRhXWRa4nrLFb+xRH9Fmw=="),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("wSInO/tKEOaLGCAY2h/7gtLWMpzyLJ0ijFh95JTpYrPzXQYgviAdL9ZgpD9EAte8On+drvhFvjIFsfQUwxbNPQ=="),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileSHA512 := MakeFileBase64Sha512Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filebase64sha512(%#v)", test.Path), func(t *testing.T) {
got, err := fileSHA512.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestBcrypt(t *testing.T) {
// single variable test
p, err := Bcrypt(cty.StringVal("test"))
@ -165,6 +255,51 @@ func TestMd5(t *testing.T) {
}
}
func TestFileMD5(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("b10a8db164e0754105b7a99be72e3fe5"),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("d7e6c283185a1078c58213beadca98b0"),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileMD5 := MakeFileMd5Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filemd5(%#v)", test.Path), func(t *testing.T) {
got, err := fileMD5.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestRsaDecrypt(t *testing.T) {
tests := []struct {
Ciphertext cty.Value
@ -268,6 +403,51 @@ func TestSha1(t *testing.T) {
}
}
func TestFileSHA1(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("0a4d55a8d778e5022fab701977c5d840bbc486d0"),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("2821bcc8379e1bd6f4f31b1e6a1fbb204b4a8be8"),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileSHA1 := MakeFileSha1Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filesha1(%#v)", test.Path), func(t *testing.T) {
got, err := fileSHA1.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestSha256(t *testing.T) {
tests := []struct {
String cty.Value
@ -301,6 +481,51 @@ func TestSha256(t *testing.T) {
}
}
func TestFileSHA256(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("e3b535abd2195b4f774a6033742f36d129299fcbc73ef73cb33b9dfd8ddece9a"),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileSHA256 := MakeFileSha256Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filesha256(%#v)", test.Path), func(t *testing.T) {
got, err := fileSHA256.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestSha512(t *testing.T) {
tests := []struct {
String cty.Value
@ -334,6 +559,51 @@ func TestSha512(t *testing.T) {
}
}
func TestFileSHA512(t *testing.T) {
tests := []struct {
Path cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("testdata/hello.txt"),
cty.StringVal("2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b"),
false,
},
{
cty.StringVal("testdata/icon.png"),
cty.StringVal("c122273bfb4a10e68b182018da1ffb82d2d6329cf22c9d228c587de494e962b3f35d0620be201d2fd660a43f4402d7bc3a7f9daef845be3205b1f414c316cd3d"),
false,
},
{
cty.StringVal("testdata/missing"),
cty.NilVal,
true, // no file exists
},
}
fileSHA512 := MakeFileSha512Func(".")
for _, test := range tests {
t.Run(fmt.Sprintf("filesha512(%#v)", test.Path), func(t *testing.T) {
got, err := fileSHA512.Call([]cty.Value{test.Path})
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
const (
CipherBase64 = "eczGaDhXDbOFRZGhjx2etVzWbRqWDlmq0bvNt284JHVbwCgObiuyX9uV0LSAMY707IEgMkExJqXmsB4OWKxvB7epRB9G/3+F+pcrQpODlDuL9oDUAsa65zEpYF0Wbn7Oh7nrMQncyUPpyr9WUlALl0gRWytOA23S+y5joa4M34KFpawFgoqTu/2EEH4Xl1zo+0fy73fEto+nfkUY+meuyGZ1nUx/+DljP7ZqxHBFSlLODmtuTMdswUbHbXbWneW51D7Jm7xB8nSdiA2JQNK5+Sg5x8aNfgvFTt/m2w2+qpsyFa5Wjeu6fZmXSl840CA07aXbk9vN4I81WmJyblD/ZA=="
PrivateKey = `

View File

@ -29,26 +29,9 @@ func MakeFileFunc(baseDir string, encBase64 bool) function.Function {
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
path := args[0].AsString()
path, err := homedir.Expand(path)
src, err := readFileBytes(baseDir, path)
if err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to expand ~: %s", err)
}
if !filepath.IsAbs(path) {
path = filepath.Join(baseDir, path)
}
// Ensure that the path is canonical for the host OS
path = filepath.Clean(path)
src, err := ioutil.ReadFile(path)
if err != nil {
// ReadFile does not return Terraform-user-friendly error
// messages, so we'll provide our own.
if os.IsNotExist(err) {
return cty.UnknownVal(cty.String), fmt.Errorf("no file exists at %s", path)
}
return cty.UnknownVal(cty.String), fmt.Errorf("failed to read %s", path)
return cty.UnknownVal(cty.String), err
}
switch {
@ -270,6 +253,32 @@ var PathExpandFunc = function.New(&function.Spec{
},
})
func readFileBytes(baseDir, path string) ([]byte, error) {
path, err := homedir.Expand(path)
if err != nil {
return nil, fmt.Errorf("failed to expand ~: %s", err)
}
if !filepath.IsAbs(path) {
path = filepath.Join(baseDir, path)
}
// Ensure that the path is canonical for the host OS
path = filepath.Clean(path)
src, err := ioutil.ReadFile(path)
if err != nil {
// ReadFile does not return Terraform-user-friendly error
// messages, so we'll provide our own.
if os.IsNotExist(err) {
return nil, fmt.Errorf("no file exists at %s", path)
}
return nil, fmt.Errorf("failed to read %s", path)
}
return src, nil
}
// File reads the contents of the file at the given path.
//
// The file must contain valid UTF-8 bytes, or this function will return an error.

View File

@ -29,86 +29,92 @@ func (s *Scope) Functions() map[string]function.Function {
// that would be useful to all applications using cty functions.
s.funcs = map[string]function.Function{
"abs": stdlib.AbsoluteFunc,
"basename": funcs.BasenameFunc,
"base64decode": funcs.Base64DecodeFunc,
"base64encode": funcs.Base64EncodeFunc,
"base64gzip": funcs.Base64GzipFunc,
"base64sha256": funcs.Base64Sha256Func,
"base64sha512": funcs.Base64Sha512Func,
"bcrypt": funcs.BcryptFunc,
"ceil": funcs.CeilFunc,
"chomp": funcs.ChompFunc,
"cidrhost": funcs.CidrHostFunc,
"cidrnetmask": funcs.CidrNetmaskFunc,
"cidrsubnet": funcs.CidrSubnetFunc,
"coalesce": stdlib.CoalesceFunc,
"coalescelist": funcs.CoalesceListFunc,
"compact": funcs.CompactFunc,
"concat": stdlib.ConcatFunc,
"contains": funcs.ContainsFunc,
"csvdecode": stdlib.CSVDecodeFunc,
"dirname": funcs.DirnameFunc,
"distinct": funcs.DistinctFunc,
"element": funcs.ElementFunc,
"chunklist": funcs.ChunklistFunc,
"file": funcs.MakeFileFunc(s.BaseDir, false),
"fileexists": funcs.MakeFileExistsFunc(s.BaseDir),
"filebase64": funcs.MakeFileFunc(s.BaseDir, true),
"flatten": funcs.FlattenFunc,
"floor": funcs.FloorFunc,
"format": stdlib.FormatFunc,
"formatdate": stdlib.FormatDateFunc,
"formatlist": stdlib.FormatListFunc,
"indent": funcs.IndentFunc,
"index": funcs.IndexFunc,
"join": funcs.JoinFunc,
"jsondecode": stdlib.JSONDecodeFunc,
"jsonencode": stdlib.JSONEncodeFunc,
"keys": funcs.KeysFunc,
"length": funcs.LengthFunc,
"list": funcs.ListFunc,
"log": funcs.LogFunc,
"lookup": funcs.LookupFunc,
"lower": stdlib.LowerFunc,
"map": funcs.MapFunc,
"matchkeys": funcs.MatchkeysFunc,
"max": stdlib.MaxFunc,
"md5": funcs.Md5Func,
"merge": funcs.MergeFunc,
"min": stdlib.MinFunc,
"pathexpand": funcs.PathExpandFunc,
"pow": funcs.PowFunc,
"replace": funcs.ReplaceFunc,
"rsadecrypt": funcs.RsaDecryptFunc,
"sethaselement": stdlib.SetHasElementFunc,
"setintersection": stdlib.SetIntersectionFunc,
"setproduct": funcs.SetProductFunc,
"setunion": stdlib.SetUnionFunc,
"sha1": funcs.Sha1Func,
"sha256": funcs.Sha256Func,
"sha512": funcs.Sha512Func,
"signum": funcs.SignumFunc,
"slice": funcs.SliceFunc,
"sort": funcs.SortFunc,
"split": funcs.SplitFunc,
"substr": stdlib.SubstrFunc,
"timestamp": funcs.TimestampFunc,
"timeadd": funcs.TimeAddFunc,
"title": funcs.TitleFunc,
"tostring": funcs.MakeToFunc(cty.String),
"tonumber": funcs.MakeToFunc(cty.Number),
"tobool": funcs.MakeToFunc(cty.Bool),
"toset": funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
"tolist": funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
"tomap": funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
"transpose": funcs.TransposeFunc,
"trimspace": funcs.TrimSpaceFunc,
"upper": stdlib.UpperFunc,
"urlencode": funcs.URLEncodeFunc,
"uuid": funcs.UUIDFunc,
"values": funcs.ValuesFunc,
"zipmap": funcs.ZipmapFunc,
"abs": stdlib.AbsoluteFunc,
"basename": funcs.BasenameFunc,
"base64decode": funcs.Base64DecodeFunc,
"base64encode": funcs.Base64EncodeFunc,
"base64gzip": funcs.Base64GzipFunc,
"base64sha256": funcs.Base64Sha256Func,
"base64sha512": funcs.Base64Sha512Func,
"bcrypt": funcs.BcryptFunc,
"ceil": funcs.CeilFunc,
"chomp": funcs.ChompFunc,
"cidrhost": funcs.CidrHostFunc,
"cidrnetmask": funcs.CidrNetmaskFunc,
"cidrsubnet": funcs.CidrSubnetFunc,
"coalesce": stdlib.CoalesceFunc,
"coalescelist": funcs.CoalesceListFunc,
"compact": funcs.CompactFunc,
"concat": stdlib.ConcatFunc,
"contains": funcs.ContainsFunc,
"csvdecode": stdlib.CSVDecodeFunc,
"dirname": funcs.DirnameFunc,
"distinct": funcs.DistinctFunc,
"element": funcs.ElementFunc,
"chunklist": funcs.ChunklistFunc,
"file": funcs.MakeFileFunc(s.BaseDir, false),
"fileexists": funcs.MakeFileExistsFunc(s.BaseDir),
"filebase64": funcs.MakeFileFunc(s.BaseDir, true),
"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
"filemd5": funcs.MakeFileMd5Func(s.BaseDir),
"filesha1": funcs.MakeFileSha1Func(s.BaseDir),
"filesha256": funcs.MakeFileSha256Func(s.BaseDir),
"filesha512": funcs.MakeFileSha512Func(s.BaseDir),
"flatten": funcs.FlattenFunc,
"floor": funcs.FloorFunc,
"format": stdlib.FormatFunc,
"formatdate": stdlib.FormatDateFunc,
"formatlist": stdlib.FormatListFunc,
"indent": funcs.IndentFunc,
"index": funcs.IndexFunc,
"join": funcs.JoinFunc,
"jsondecode": stdlib.JSONDecodeFunc,
"jsonencode": stdlib.JSONEncodeFunc,
"keys": funcs.KeysFunc,
"length": funcs.LengthFunc,
"list": funcs.ListFunc,
"log": funcs.LogFunc,
"lookup": funcs.LookupFunc,
"lower": stdlib.LowerFunc,
"map": funcs.MapFunc,
"matchkeys": funcs.MatchkeysFunc,
"max": stdlib.MaxFunc,
"md5": funcs.Md5Func,
"merge": funcs.MergeFunc,
"min": stdlib.MinFunc,
"pathexpand": funcs.PathExpandFunc,
"pow": funcs.PowFunc,
"replace": funcs.ReplaceFunc,
"rsadecrypt": funcs.RsaDecryptFunc,
"sethaselement": stdlib.SetHasElementFunc,
"setintersection": stdlib.SetIntersectionFunc,
"setproduct": funcs.SetProductFunc,
"setunion": stdlib.SetUnionFunc,
"sha1": funcs.Sha1Func,
"sha256": funcs.Sha256Func,
"sha512": funcs.Sha512Func,
"signum": funcs.SignumFunc,
"slice": funcs.SliceFunc,
"sort": funcs.SortFunc,
"split": funcs.SplitFunc,
"substr": stdlib.SubstrFunc,
"timestamp": funcs.TimestampFunc,
"timeadd": funcs.TimeAddFunc,
"title": funcs.TitleFunc,
"tostring": funcs.MakeToFunc(cty.String),
"tonumber": funcs.MakeToFunc(cty.Number),
"tobool": funcs.MakeToFunc(cty.Bool),
"toset": funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
"tolist": funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
"tomap": funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
"transpose": funcs.TransposeFunc,
"trimspace": funcs.TrimSpaceFunc,
"upper": stdlib.UpperFunc,
"urlencode": funcs.URLEncodeFunc,
"uuid": funcs.UUIDFunc,
"values": funcs.ValuesFunc,
"zipmap": funcs.ZipmapFunc,
}
s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {

View File

@ -27,5 +27,7 @@ uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
## Related Functions
* [`filebase64sha256`](./filebase64sha256.html) calculates the same hash from
the contents of a file rather than from a string value.
* [`sha256`](./sha256.html) calculates the same hash but returns the result
in a more-verbose hexadecimal encoding.

View File

@ -27,5 +27,7 @@ MJ7MSJwS1utMxA9QyQLytNDtd+5RGnx6m808qG1M2G+YndNbxf9JlnDaNCVbRbDP2DDoH2Bdz33FVC6T
## Related Functions
* [`filebase64sha512`](./filebase64sha512.html) calculates the same hash from
the contents of a file rather than from a string value.
* [`sha512`](./sha512.html) calculates the same hash but returns the result
in a more-verbose hexadecimal encoding.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filebase64sha256 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filebase64sha256"
description: |-
The filebase64sha256 function computes the SHA256 hash of the contents of
a given file and encodes it with Base64.
---
# `filebase64sha256` Function
`filebase64sha256` is a variant of [`base64sha256`](./base64sha256.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `base64sha256(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filebase64sha512 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filebase64sha512"
description: |-
The filebase64sha512 function computes the SHA512 hash of the contents of
a given file and encodes it with Base64.
---
# `filebase64sha512` Function
`filebase64sha512` is a variant of [`base64sha512`](./base64sha512.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `base64sha512(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filemd5 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filemd5"
description: |-
The filemd5 function computes the MD5 hash of the contents of
a given file and encodes it as hex.
---
# `filemd5` Function
`filemd5` is a variant of [`md5`](./md5.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `md5(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filesha1 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filesha1"
description: |-
The filesha1 function computes the SHA1 hash of the contents of
a given file and encodes it as hex.
---
# `filesha1` Function
`filesha1` is a variant of [`sha1`](./sha1.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `sha1(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filesha256 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filesha256"
description: |-
The filesha256 function computes the SHA256 hash of the contents of
a given file and encodes it as hex.
---
# `filesha256` Function
`filesha256` is a variant of [`sha256`](./sha256.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `sha256(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -0,0 +1,17 @@
---
layout: "functions"
page_title: "filesha512 - Functions - Configuration Language"
sidebar_current: "docs-funcs-crypto-filesha512"
description: |-
The filesha512 function computes the SHA512 hash of the contents of
a given file and encodes it as hex.
---
# `filesha512` Function
`filesha512` is a variant of [`sha512`](./sha512.html)
that hashes the contents of a given file rather than a literal string.
This is similar to `sha512(file(filename))`, but
because [`file`](./file.html) accepts only UTF-8 text it cannot be used to
create hashes for binary files.

View File

@ -26,3 +26,8 @@ considerations applying to the MD5 algorithm.
> md5("hello world")
5eb63bbbe01eeed093cb22bb8f5acdc3
```
## Related Functions
* [`filemd5`](./filemd5.html) calculates the same hash from
the contents of a file rather than from a string value.

View File

@ -26,3 +26,8 @@ relevant literature to understand the security implications.
> sha1("hello world")
2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
```
## Related Functions
* [`filesha1`](./filesha1.html) calculates the same hash from
the contents of a file rather than from a string value.

View File

@ -25,5 +25,10 @@ b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
## Related Functions
## Related Functions
* [`filesha256`](./filesha256.html) calculates the same hash from
the contents of a file rather than from a string value.
* [`base64sha256`](./base64sha256.html) calculates the same hash but returns
the result in a more-compact Base64 encoding.

View File

@ -25,5 +25,7 @@ then encoded to lowercase hexadecimal digits before returning.
## Related Functions
* [`filesha512`](./filesha512.html) calculates the same hash from
the contents of a file rather than from a string value.
* [`base64sha512`](./base64sha512.html) calculates the same hash but returns
the result in a more-compact Base64 encoding.

View File

@ -311,6 +311,30 @@
<a href="/docs/configuration/functions/bcrypt.html">bcrypt</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filebase64sha256") %>>
<a href="/docs/configuration/functions/filebase64sha256.html">filebase64sha256</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filebase64sha512") %>>
<a href="/docs/configuration/functions/filebase64sha512.html">filebase64sha512</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filemd5") %>>
<a href="/docs/configuration/functions/filemd5.html">filemd5</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filesha1") %>>
<a href="/docs/configuration/functions/filesha1.html">filesha1</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filesha256") %>>
<a href="/docs/configuration/functions/filesha256.html">filesha256</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-filesha512") %>>
<a href="/docs/configuration/functions/filesha512.html">filesha512</a>
</li>
<li<%= sidebar_current("docs-funcs-crypto-md5") %>>
<a href="/docs/configuration/functions/md5.html">md5</a>
</li>