I was researching how to use Golang's Template.FuncMap()
and found a data access issue in:
https://www.calhoun.io/intro-to-templates-p3-functions/
The section in question:
# Making our functions globally useful
Next we need to define our function that uses a closure. This is basically a fancy way of saying we are
going to define a dynamic function that has access to variables that are not necessarily passed into it,
but are available when we define the function.
A Go Template object is created as global singleton:
var testTemplate *template.Template
A temporary hasPermission()
function is defined during initialization so the hello.gohtml
template can be correctly
parsed.
testTemplate, err = template.New("hello.gohtml").Funcs(template.FuncMap{
"hasPermission": func(feature string) bool {
return false
},
The intention is to change out the hasPermission
function for each request. Changing the FuncMap
is specifically allowed
in the Template.Funcs()
documentation: "It is legal to overwrite
elements of the map"
This closure captures a User
object and this function is passed the global singleton testTemplate
. This works correctly
during tests. The User
object contains the expected "correct" (AKA fake) user data.
Not under load though. Do not assume strict goroutine procedural order in a multiprocessing environment. Template.Funcs()
can be called by two goroutines in nearly the same moment, so that later when they separately call Template.Execute()
they
will call the exact same hasPermission()
function. hasPermission()
function can be changed "out from under" the request.
This can result in any number of security bugs or other serious issues in a production application.
See code/comments below for details of a modified example that will Fatal()
during data access problems.