blueprints: Fix handling of invalid blueprint names in the API code

Empty names are not allowed, and blueprint names should only contain
characters matching: ^[a-zA-Z0-9._-]+$

This also adds tests for the various places where the blueprint name
could potentially be wrong.
This commit is contained in:
Brian C. Lane 2020-05-12 11:31:21 -07:00 committed by Ondřej Budai
parent 56ae3d33c8
commit 369312989f
4 changed files with 392 additions and 24 deletions

View file

@ -63,6 +63,42 @@ func TestPostEmptyTOMLBlueprintV0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// POST a TOML blueprint with an empty name
func TestPostEmptyNameTOMLBlueprintV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `
name=""
version="0.0.1"
[package]
name="bash"
version="*"
`
resp, err := PostTOMLBlueprintV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a TOML blueprint with an invalid name chars
func TestPostInvalidNameTOMLBlueprintV0(t *testing.T) {
// Use a blueprint with invalid Name
bp := `
name="I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜"
version="0.0.1"
[package]
name="bash"
version="*"
`
resp, err := PostTOMLBlueprintV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a new JSON blueprint
func TestPostJSONBlueprintV0(t *testing.T) {
bp := `{
@ -100,6 +136,40 @@ func TestPostEmptyJSONBlueprintV0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// POST a JSON blueprint with an empty name
func TestPostEmptyNameJSONBlueprintV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `{
"name": "",
"version": "0.0.1",
"modules": [{"name": "util-linux", "version": "*"}]
}`
resp, err := PostJSONBlueprintV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a JSON blueprint with invalid name chars
func TestPostInvalidNameJSONBlueprintV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `{
"name": "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜",
"version": "0.0.1",
"modules": [{"name": "util-linux", "version": "*"}]
}`
resp, err := PostJSONBlueprintV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a blueprint to the workspace as TOML
func TestPostTOMLWorkspaceV0(t *testing.T) {
bp := `
@ -145,6 +215,42 @@ func TestPostEmptyTOMLWorkspaceV0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// POST a TOML blueprint with an empty name to the workspace
func TestPostEmptyNameTOMLWorkspaceV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `
name=""
version="0.0.1"
[package]
name="bash"
version="*"
`
resp, err := PostTOMLWorkspaceV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a TOML blueprint with an invalid name chars to the workspace
func TestPostInvalidNameTOMLWorkspaceV0(t *testing.T) {
// Use a blueprint with invalid Name
bp := `
name="I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜"
version="0.0.1"
[package]
name="bash"
version="*"
`
resp, err := PostTOMLWorkspaceV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a blueprint to the workspace as JSON
func TestPostJSONWorkspaceV0(t *testing.T) {
bp := `{
@ -182,6 +288,40 @@ func TestPostEmptyJSONWorkspaceV0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// POST a JSON blueprint with an empty name to the workspace
func TestPostEmptyNameJSONWorkspaceV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `{
"name": "",
"version": "0.0.1",
"modules": [{"name": "util-linux", "version": "*"}]
}`
resp, err := PostJSONWorkspaceV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// POST a JSON blueprint with invalid name chars to the workspace
func TestPostInvalidNameJSONWorkspaceV0(t *testing.T) {
// Use a blueprint with an empty Name
bp := `{
"name": "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜",
"version": "0.0.1",
"modules": [{"name": "util-linux", "version": "*"}]
}`
resp, err := PostJSONWorkspaceV0(testState.socket, bp)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// delete a blueprint
func TestDeleteBlueprintV0(t *testing.T) {
// POST a blueprint to delete
@ -211,6 +351,16 @@ func TestDeleteNonBlueprint0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// delete a blueprint with invalid name characters
func TestDeleteInvalidBlueprintV0(t *testing.T) {
resp, err := DeleteBlueprintV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// delete a new blueprint from the workspace
func TestDeleteNewWorkspaceV0(t *testing.T) {
// POST a blueprint to delete
@ -291,6 +441,23 @@ func TestDeleteChangesWorkspaceV0(t *testing.T) {
require.Equal(t, "deleteBlueprintChangesWSV0", info.Blueprints[0].Description, "original blueprint not returned")
}
// delete a non-existent blueprint workspace
func TestDeleteNonWorkspace0(t *testing.T) {
resp, err := DeleteWorkspaceV0(testState.socket, "test-delete-non-blueprint-ws-v0")
require.NoError(t, err, "failed with a client error")
require.False(t, resp.Status, "did not return an error")
}
// delete a blueprint with invalid name characters
func TestDeleteInvalidWorkspaceV0(t *testing.T) {
resp, err := DeleteWorkspaceV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// list blueprints
func TestListBlueprintsV0(t *testing.T) {
// Post a couple of blueprints
@ -361,6 +528,16 @@ func TestGetNonTOMLBlueprintV0(t *testing.T) {
require.False(t, api.Status, "wrong Status (true)")
}
// get blueprint with invalid name characters
func TestGetInvalidTOMLBlueprintV0(t *testing.T) {
_, api, err := GetBlueprintInfoTOMLV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, api, "did not return an error")
require.False(t, api.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", api.Errors[0].ID)
require.Contains(t, api.Errors[0].Msg, "Invalid characters in API path")
}
// get blueprint contents as JSON
func TestGetJSONBlueprintV0(t *testing.T) {
bp := `{
@ -490,6 +667,16 @@ func TestBlueprintNonChangesV0(t *testing.T) {
require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
}
// get changes with invalid name characters
func TestInvalidBlueprintChangesV0(t *testing.T) {
_, api, err := GetBlueprintsChangesV0(testState.socket, []string{"I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜"})
require.NoError(t, err, "failed with a client error")
require.NotNil(t, api, "did not return an error")
require.False(t, api.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", api.Errors[0].ID)
require.Contains(t, api.Errors[0].Msg, "Invalid characters in API path")
}
// Undo blueprint changes
func TestUndoBlueprintV0(t *testing.T) {
bps := []string{`{
@ -589,6 +776,26 @@ func TestUndoNonBlueprintV0(t *testing.T) {
require.False(t, resp.Status, "did not return an error")
}
// undo a blueprint with invalid name characters
func TestUndoInvalidBlueprintV0(t *testing.T) {
resp, err := UndoBlueprintChangeV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜", "FFFF")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// undo a blueprint with invalid commit characters
func TestUndoInvalidBlueprintCommitV0(t *testing.T) {
resp, err := UndoBlueprintChangeV0(testState.socket, "test-undo-non-blueprint-v0", "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// Tag a blueprint with a new revision
// The blueprint revision tag cannot be reset, it always increments by one, and cannot be deleted.
// So to test tagging we tag two blueprint changes and make sure the second is first +1
@ -660,6 +867,16 @@ func TestNonBlueprintTagV0(t *testing.T) {
require.False(t, tagResp.Status, "did not return an error")
}
// tag a blueprint with invalid name characters
func TestTagInvalidBlueprintV0(t *testing.T) {
resp, err := TagBlueprintV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp, "did not return an error")
require.False(t, resp.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// depsolve a blueprint with packages and modules
func TestBlueprintDepsolveV0(t *testing.T) {
bp := `{
@ -695,6 +912,16 @@ func TestNonBlueprintDepsolveV0(t *testing.T) {
require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
}
// depsolve a blueprint with invalid name characters
func TestDepsolveInvalidBlueprintV0(t *testing.T) {
_, api, err := DepsolveBlueprintV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, api, "did not return an error")
require.False(t, api.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", api.Errors[0].ID)
require.Contains(t, api.Errors[0].Msg, "Invalid characters in API path")
}
// freeze a blueprint
func TestBlueprintFreezeV0(t *testing.T) {
if testState.unitTest {
@ -758,4 +985,14 @@ func TestNonBlueprintFreezeV0(t *testing.T) {
require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
}
// freeze a blueprint with invalid name characters
func TestFreezeInvalidBlueprintV0(t *testing.T) {
_, api, err := FreezeBlueprintV0(testState.socket, "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, api, "did not return an error")
require.False(t, api.Status, "wrong Status (true)")
require.Equal(t, "InvalidChars", api.Errors[0].ID)
require.Contains(t, api.Errors[0].Msg, "Invalid characters in API path")
}
// TODO diff of blueprint changes

View file

@ -89,6 +89,36 @@ func TestComposeInvalidBlueprintV0(t *testing.T) {
require.Contains(t, resp.Errors[0].Msg, "test-invalid-bp-compose-v0")
}
// Test compose for empty blueprint fails
func TestComposeEmptyBlueprintV0(t *testing.T) {
compose := `{
"blueprint_name": "",
"compose_type": "qcow2",
"branch": "master"
}`
resp, err := PostComposeV0(testState.socket, compose)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp)
require.False(t, resp.Status, "POST did not fail")
require.Equal(t, len(resp.Errors), 1)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// Test compose for blueprint with invalid characters fails
func TestComposeInvalidCharsBlueprintV0(t *testing.T) {
compose := `{
"blueprint_name": "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜",
"compose_type": "qcow2",
"branch": "master"
}`
resp, err := PostComposeV0(testState.socket, compose)
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp)
require.False(t, resp.Status, "POST did not fail")
require.Equal(t, len(resp.Errors), 1)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
}
// Test compose cancel for unknown uuid fails
// Is cancel implemented at all?
@ -162,6 +192,24 @@ func TestComposeInvalidStatusV0(t *testing.T) {
require.Equal(t, 0, len(status))
}
// Test status filter for unknown blueprint
func TestComposeUnknownBlueprintStatusV0(t *testing.T) {
status, resp, err := GetComposeStatusV0(testState.socket, "*", "unknown-blueprint-test", "", "")
require.NoError(t, err, "failed with a client error")
require.Nil(t, resp)
require.Equal(t, 0, len(status))
}
// Test status filter for blueprint with invalid characters
func TestComposeInvalidBlueprintStatusV0(t *testing.T) {
status, resp, err := GetComposeStatusV0(testState.socket, "*", "I 𝒊ll 𝟉ο𝘁 𝛠𝔰 𝘁𝒉𝝸𝚜", "", "")
require.NoError(t, err, "failed with a client error")
require.NotNil(t, resp)
require.Equal(t, "InvalidChars", resp.Errors[0].ID)
require.Contains(t, resp.Errors[0].Msg, "Invalid characters in API path")
require.Equal(t, 0, len(status))
}
// Helper for searching compose results for a UUID
func UUIDInComposeResults(buildID uuid.UUID, results []weldr.ComposeEntryV0) bool {
for idx := range results {

View file

@ -11,6 +11,7 @@ import (
"net"
"net/http"
"net/url"
"regexp"
"sort"
"strconv"
"strings"
@ -43,6 +44,8 @@ type API struct {
router *httprouter.Router
}
var ValidBlueprintName = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
func New(rpmmd rpmmd.RPMMD, arch distro.Arch, distro distro.Distro, repos []rpmmd.RepoConfig, logger *log.Logger, store *store.Store, workers *worker.Server) *API {
api := &API{
store: store,
@ -232,6 +235,24 @@ type responseError struct {
Msg string `json:"msg"`
}
// verifyStringsWithRegex checks a slive of strings against a regex of allowed characters
// it writes the InvalidChars error to the writer and returns false if any of them fail the check
// It will also return an error if the string is empty
func verifyStringsWithRegex(writer http.ResponseWriter, strings []string, re *regexp.Regexp) bool {
for _, s := range strings {
if len(s) > 0 && re.MatchString(s) {
continue
}
errors := responseError{
ID: "InvalidChars",
Msg: "Invalid characters in API path",
}
statusResponseError(writer, http.StatusBadRequest, errors)
return false
}
return true
}
func statusResponseError(writer http.ResponseWriter, code int, errors ...responseError) {
type reply struct {
Status bool `json:"status"`
@ -807,6 +828,13 @@ func (api *API) blueprintsInfoHandler(writer http.ResponseWriter, request *http.
return
}
// Remove the leading / from the first entry (check above ensures it is not just a /
names[0] = names[0][1:]
if !verifyStringsWithRegex(writer, names, ValidBlueprintName) {
return
}
query, err := url.ParseQuery(request.URL.RawQuery)
if err != nil {
errors := responseError{
@ -821,12 +849,7 @@ func (api *API) blueprintsInfoHandler(writer http.ResponseWriter, request *http.
changes := []change{}
blueprintErrors := []responseError{}
for i, name := range names {
// remove leading / from first name
if i == 0 {
name = name[1:]
}
for _, name := range names {
blueprint, changed := api.store.GetBlueprint(name)
if blueprint == nil {
blueprintErrors = append(blueprintErrors, responseError{
@ -902,13 +925,16 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
return
}
// Remove the leading / from the first entry (check above ensures it is not just a /
names[0] = names[0][1:]
if !verifyStringsWithRegex(writer, names, ValidBlueprintName) {
return
}
blueprints := []entry{}
blueprintsErrors := []responseError{}
for i, name := range names {
// remove leading / from first name
if i == 0 {
name = name[1:]
}
for _, name := range names {
blueprint, _ := api.store.GetBlueprint(name)
if blueprint == nil {
blueprintsErrors = append(blueprintsErrors, responseError{
@ -987,13 +1013,16 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
return
}
// Remove the leading / from the first entry (check above ensures it is not just a /
names[0] = names[0][1:]
if !verifyStringsWithRegex(writer, names, ValidBlueprintName) {
return
}
blueprints := []blueprintFrozen{}
errors := []responseError{}
for i, name := range names {
// remove leading / from first name
if i == 0 {
name = name[1:]
}
for _, name := range names {
bp, _ := api.store.GetBlueprint(name)
if bp == nil {
rerr := responseError{
@ -1076,8 +1105,19 @@ func (api *API) blueprintsDiffHandler(writer http.ResponseWriter, request *http.
}
name := params.ByName("blueprint")
if !verifyStringsWithRegex(writer, []string{name}, ValidBlueprintName) {
return
}
fromCommit := params.ByName("from")
if !verifyStringsWithRegex(writer, []string{fromCommit}, ValidBlueprintName) {
return
}
toCommit := params.ByName("to")
if !verifyStringsWithRegex(writer, []string{toCommit}, ValidBlueprintName) {
return
}
if len(name) == 0 || len(fromCommit) == 0 || len(toCommit) == 0 {
errors := responseError{
@ -1178,6 +1218,13 @@ func (api *API) blueprintsChangesHandler(writer http.ResponseWriter, request *ht
return
}
// Remove the leading / from the first entry (check above ensures it is not just a /
names[0] = names[0][1:]
if !verifyStringsWithRegex(writer, names, ValidBlueprintName) {
return
}
offset, limit, err := parseOffsetAndLimit(request.URL.Query())
if err != nil {
errors := responseError{
@ -1190,11 +1237,7 @@ func (api *API) blueprintsChangesHandler(writer http.ResponseWriter, request *ht
allChanges := []change{}
errors := []responseError{}
for i, name := range names {
// remove leading / from first name
if i == 0 {
name = name[1:]
}
for _, name := range names {
bpChanges := api.store.GetBlueprintChanges(name)
// Reverse the changes, newest first
reversed := make([]blueprint.Change, 0, len(bpChanges))
@ -1269,6 +1312,10 @@ func (api *API) blueprintsNewHandler(writer http.ResponseWriter, request *http.R
return
}
if !verifyStringsWithRegex(writer, []string{blueprint.Name}, ValidBlueprintName) {
return
}
commitMsg := "Recipe " + blueprint.Name + ", version " + blueprint.Version + " saved."
err = api.store.PushBlueprint(blueprint, commitMsg)
if err != nil {
@ -1326,6 +1373,10 @@ func (api *API) blueprintsWorkspaceHandler(writer http.ResponseWriter, request *
return
}
if !verifyStringsWithRegex(writer, []string{blueprint.Name}, ValidBlueprintName) {
return
}
err = api.store.PushBlueprintToWorkspace(blueprint)
if err != nil {
errors := responseError{
@ -1345,7 +1396,15 @@ func (api *API) blueprintUndoHandler(writer http.ResponseWriter, request *http.R
}
name := params.ByName("blueprint")
if !verifyStringsWithRegex(writer, []string{name}, ValidBlueprintName) {
return
}
commit := params.ByName("commit")
if !verifyStringsWithRegex(writer, []string{commit}, ValidBlueprintName) {
return
}
bpChange, err := api.store.GetBlueprintChange(name, commit)
if err != nil {
errors := responseError{
@ -1375,7 +1434,12 @@ func (api *API) blueprintDeleteHandler(writer http.ResponseWriter, request *http
return
}
if err := api.store.DeleteBlueprint(params.ByName("blueprint")); err != nil {
name := params.ByName("blueprint")
if !verifyStringsWithRegex(writer, []string{name}, ValidBlueprintName) {
return
}
if err := api.store.DeleteBlueprint(name); err != nil {
errors := responseError{
ID: "BlueprintsError",
Msg: err.Error(),
@ -1391,7 +1455,12 @@ func (api *API) blueprintDeleteWorkspaceHandler(writer http.ResponseWriter, requ
return
}
if err := api.store.DeleteBlueprintFromWorkspace(params.ByName("blueprint")); err != nil {
name := params.ByName("blueprint")
if !verifyStringsWithRegex(writer, []string{name}, ValidBlueprintName) {
return
}
if err := api.store.DeleteBlueprintFromWorkspace(name); err != nil {
errors := responseError{
ID: "BlueprintsError",
Msg: err.Error(),
@ -1408,7 +1477,12 @@ func (api *API) blueprintsTagHandler(writer http.ResponseWriter, request *http.R
return
}
err := api.store.TagBlueprint(params.ByName("blueprint"))
name := params.ByName("blueprint")
if !verifyStringsWithRegex(writer, []string{name}, ValidBlueprintName) {
return
}
err := api.store.TagBlueprint(name)
if err != nil {
errors := responseError{
ID: "BlueprintsError",
@ -1472,6 +1546,10 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
return
}
if !verifyStringsWithRegex(writer, []string{cr.BlueprintName}, ValidBlueprintName) {
return
}
composeID := uuid.New()
var targets []*target.Target
@ -1727,6 +1805,10 @@ func (api *API) composeStatusHandler(writer http.ResponseWriter, request *http.R
}
filterBlueprint := q.Get("blueprint")
if len(filterBlueprint) > 0 && !verifyStringsWithRegex(writer, []string{filterBlueprint}, ValidBlueprintName) {
return
}
filterStatus := q.Get("status")
filterImageType, filterImageTypeExists := common.ImageTypeFromCompatString(q.Get("type"))

View file

@ -79,6 +79,7 @@ func TestBlueprintsNew(t *testing.T) {
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[],"version":""}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages:}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"400 Bad Request: The browser (or proxy) sent a request that this server could not understand: unexpected EOF"}]}`},
{"POST", "/api/v0/blueprints/new", `{"name":"","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"InvalidChars","msg":"Invalid characters in API path"}]}`},
{"POST", "/api/v0/blueprints/new", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"Missing blueprint"}]}`},
}