Skip to content

Instantly share code, notes, and snippets.

@mvdan
Created October 15, 2017 16:09
Show Gist options
  • Save mvdan/25fb3b01a05866db01884066339e6e88 to your computer and use it in GitHub Desktop.
Save mvdan/25fb3b01a05866db01884066339e6e88 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"io"
"log"
"os"
"strings"
"mvdan.cc/sh/interp"
"mvdan.cc/sh/syntax"
)
const src = `
name=firefox
version=52.4.0esr
release=1
source=(https://ftp.mozilla.org/pub/firefox/releases/$version/source/firefox-$version.source.tar.xz
firefox-install-dir.patch firefox.desktop)
# uncomment lines below to see what is allowed
#ok_prog=$(echo foo | sed 's/o/a/g')
#ok_file=$(echo prog >/dev/null)
#hack=$(upload ~/.ssh)
`
func main() {
strs, err := extract(src, "source")
if err != nil {
log.Fatal(err)
}
// use strings.Join to mimic "echo ..."
fmt.Println(strs)
}
func extract(src, name string) ([]string, error) {
p := syntax.NewParser()
file, err := p.Parse(strings.NewReader(src), "")
if err != nil {
return nil, fmt.Errorf("could not parse: %v", err)
}
r := interp.Runner{}
r.Exec = func(ctx interp.Ctxt, name string, args []string) error {
switch name {
case "sed", "grep":
default:
return fmt.Errorf("blacklisted: %s", name)
}
return interp.DefaultExec(ctx, name, args)
}
r.Open = func(ctx interp.Ctxt, path string, flags int, mode os.FileMode) (io.ReadWriteCloser, error) {
// won't pass on windows, but ok for now
if !strings.HasPrefix(path, "/dev/") {
return nil, fmt.Errorf("non-dev: %s", path)
}
return interp.DefaultOpen(ctx, path, flags, mode)
}
r.Reset()
if err := r.Run(file); err != nil {
return nil, fmt.Errorf("could not run: %v", err)
}
// verbosity below is ${name[@]}
fields := r.Fields([]*syntax.Word{
{Parts: []syntax.WordPart{
&syntax.ParamExp{
Param: &syntax.Lit{Value: name},
Index: &syntax.Word{Parts: []syntax.WordPart{&syntax.Lit{Value: "@"}}},
},
}},
})
return fields, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment