708 lines
19 KiB
Go
708 lines
19 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
neturl "net/url"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"os/signal"
|
||
|
"path/filepath"
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
|
||
|
"boringssl.googlesource.com/boringssl/util/fipstools/acvp/acvptool/acvp"
|
||
|
"golang.org/x/crypto/ssh/terminal"
|
||
|
)
|
||
|
|
||
|
func updateTerminalSize(term *terminal.Terminal) {
|
||
|
width, height, err := terminal.GetSize(0)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
term.SetSize(width, height)
|
||
|
}
|
||
|
|
||
|
func skipWS(node *node32) *node32 {
|
||
|
for ; node != nil && node.pegRule == ruleWS; node = node.next {
|
||
|
}
|
||
|
return node
|
||
|
}
|
||
|
|
||
|
func assertNodeType(node *node32, rule pegRule) {
|
||
|
if node.pegRule != rule {
|
||
|
panic(fmt.Sprintf("expected %q, found %q", rul3s[rule], rul3s[node.pegRule]))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Object interface {
|
||
|
String() (string, error)
|
||
|
Index(string) (Object, error)
|
||
|
Search(acvp.Query) (Object, error)
|
||
|
Action(action string, args []string) error
|
||
|
}
|
||
|
|
||
|
type ServerObjectSet struct {
|
||
|
env *Env
|
||
|
name string
|
||
|
searchKeys map[string][]acvp.Relation
|
||
|
resultType reflect.Type
|
||
|
subObjects map[string]func(*Env, string) (Object, error)
|
||
|
canEnumerate bool
|
||
|
}
|
||
|
|
||
|
func (set ServerObjectSet) String() (string, error) {
|
||
|
if !set.canEnumerate {
|
||
|
return "[object set " + set.name + "]", nil
|
||
|
}
|
||
|
|
||
|
data := reflect.New(reflect.SliceOf(set.resultType)).Interface()
|
||
|
if err := set.env.server.GetPaged(data, "acvp/v1/"+set.name, nil); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(data, "", " ")
|
||
|
return string(ret), err
|
||
|
}
|
||
|
|
||
|
func (set ServerObjectSet) Index(indexStr string) (Object, error) {
|
||
|
index, err := strconv.ParseUint(indexStr, 0, 64)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("object set indexes must be unsigned integers, trying to parse %q failed: %s", indexStr, err)
|
||
|
}
|
||
|
return ServerObject{&set, index}, nil
|
||
|
}
|
||
|
|
||
|
func (set ServerObjectSet) Search(condition acvp.Query) (Object, error) {
|
||
|
if set.searchKeys == nil {
|
||
|
return nil, errors.New("this object set cannot be searched")
|
||
|
}
|
||
|
|
||
|
for _, conj := range condition {
|
||
|
NextCondition:
|
||
|
for _, cond := range conj {
|
||
|
allowed, ok := set.searchKeys[cond.Param]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("search key %q not valid for this object set", cond.Param)
|
||
|
}
|
||
|
|
||
|
for _, rel := range allowed {
|
||
|
if rel == cond.Relation {
|
||
|
continue NextCondition
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil, fmt.Errorf("search key %q cannot be used with relation %q", cond.Param, cond.Relation.String())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Search{ServerObjectSet: set, query: condition}, nil
|
||
|
}
|
||
|
|
||
|
func (set ServerObjectSet) Action(action string, args []string) error {
|
||
|
switch action {
|
||
|
default:
|
||
|
return fmt.Errorf("unknown action %q", action)
|
||
|
|
||
|
case "new":
|
||
|
if len(args) != 0 {
|
||
|
return fmt.Errorf("found %d arguments but %q takes none", len(args), action)
|
||
|
}
|
||
|
|
||
|
newContents, err := edit("")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if strings.TrimSpace(string(newContents)) == "" {
|
||
|
io.WriteString(set.env.term, "Resulting file was empty. Ignoring.\n")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var result map[string]interface{}
|
||
|
if err := set.env.server.Post(&result, "acvp/v1/"+set.name, newContents); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// In case it's a testSession that was just created, poke any access token
|
||
|
// into the server's lookup table and the cache.
|
||
|
if urlInterface, ok := result["url"]; ok {
|
||
|
if url, ok := urlInterface.(string); ok {
|
||
|
if tokenInterface, ok := result["accessToken"]; ok {
|
||
|
if token, ok := tokenInterface.(string); ok {
|
||
|
for strings.HasPrefix(url, "/") {
|
||
|
url = url[1:]
|
||
|
}
|
||
|
set.env.server.PrefixTokens[url] = token
|
||
|
if len(set.env.config.SessionTokensCache) > 0 {
|
||
|
ioutil.WriteFile(filepath.Join(set.env.config.SessionTokensCache, neturl.PathEscape(url))+".token", []byte(token), 0600)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ret, err := json.MarshalIndent(result, "", " ")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
set.env.term.Write(ret)
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type ServerObject struct {
|
||
|
set *ServerObjectSet
|
||
|
index uint64
|
||
|
}
|
||
|
|
||
|
func (obj ServerObject) String() (string, error) {
|
||
|
data := reflect.New(obj.set.resultType).Interface()
|
||
|
if err := obj.set.env.server.Get(data, "acvp/v1/"+obj.set.name+"/"+strconv.FormatUint(obj.index, 10)); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(data, "", " ")
|
||
|
return string(ret), err
|
||
|
}
|
||
|
|
||
|
func (obj ServerObject) Index(index string) (Object, error) {
|
||
|
if obj.set.subObjects == nil {
|
||
|
return nil, errors.New("cannot index " + obj.set.name + " objects")
|
||
|
}
|
||
|
constr, ok := obj.set.subObjects[index]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("no such subobject %q", index)
|
||
|
}
|
||
|
return constr(obj.set.env, fmt.Sprintf("%s/%d", obj.set.name, obj.index))
|
||
|
}
|
||
|
|
||
|
func (ServerObject) Search(condition acvp.Query) (Object, error) {
|
||
|
return nil, errors.New("cannot search individual object")
|
||
|
}
|
||
|
|
||
|
func edit(initialContents string) ([]byte, error) {
|
||
|
tmp, err := ioutil.TempFile("", "acvp*.json")
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
path := tmp.Name()
|
||
|
defer os.Remove(path)
|
||
|
|
||
|
_, err = io.WriteString(tmp, initialContents)
|
||
|
tmp.Close()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
editor := os.Getenv("EDITOR")
|
||
|
if len(editor) == 0 {
|
||
|
editor = "vim"
|
||
|
}
|
||
|
|
||
|
cmd := exec.Command(editor, path)
|
||
|
cmd.Stdout = os.Stdout
|
||
|
cmd.Stdin = os.Stdin
|
||
|
cmd.Stderr = os.Stderr
|
||
|
if err := cmd.Run(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return ioutil.ReadFile(path)
|
||
|
}
|
||
|
|
||
|
func (obj ServerObject) Action(action string, args []string) error {
|
||
|
switch action {
|
||
|
default:
|
||
|
return fmt.Errorf("unknown action %q", action)
|
||
|
|
||
|
case "edit":
|
||
|
if len(args) != 0 {
|
||
|
return fmt.Errorf("found %d arguments but %q takes none", len(args), action)
|
||
|
}
|
||
|
|
||
|
contents, err := obj.String()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
newContents, err := edit(contents)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if trimmed := strings.TrimSpace(string(newContents)); len(trimmed) == 0 || trimmed == strings.TrimSpace(contents) {
|
||
|
io.WriteString(obj.set.env.term, "Resulting file was equal or empty. Not updating.\n")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var status acvp.RequestStatus
|
||
|
if err := obj.set.env.server.Put(&status, "acvp/v1/"+obj.set.name+"/"+strconv.FormatUint(obj.index, 10), newContents); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
fmt.Fprintf(obj.set.env.term, "%#v\n", status)
|
||
|
return nil
|
||
|
|
||
|
case "delete":
|
||
|
if len(args) != 0 {
|
||
|
return fmt.Errorf("found %d arguments but %q takes none", len(args), action)
|
||
|
}
|
||
|
return obj.set.env.server.Delete("acvp/v1/" + obj.set.name + "/" + strconv.FormatUint(obj.index, 10))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Search struct {
|
||
|
ServerObjectSet
|
||
|
query acvp.Query
|
||
|
}
|
||
|
|
||
|
func (search Search) String() (string, error) {
|
||
|
data := reflect.New(reflect.SliceOf(search.resultType)).Interface()
|
||
|
fmt.Printf("Searching for %#v\n", search.query)
|
||
|
if err := search.env.server.GetPaged(data, "acvp/v1/"+search.name, search.query); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(data, "", " ")
|
||
|
return string(ret), err
|
||
|
}
|
||
|
|
||
|
func (search Search) Index(_ string) (Object, error) {
|
||
|
return nil, errors.New("indexing of search results not supported")
|
||
|
}
|
||
|
|
||
|
func (search Search) Search(condition acvp.Query) (Object, error) {
|
||
|
search.query = append(search.query, condition...)
|
||
|
return search, nil
|
||
|
}
|
||
|
|
||
|
func (Search) Action(_ string, _ []string) error {
|
||
|
return errors.New("no actions supported on search objects")
|
||
|
}
|
||
|
|
||
|
type Algorithms struct {
|
||
|
ServerObjectSet
|
||
|
}
|
||
|
|
||
|
func (algos Algorithms) String() (string, error) {
|
||
|
var result struct {
|
||
|
Algorithms []map[string]interface{} `json:"algorithms"`
|
||
|
}
|
||
|
if err := algos.env.server.Get(&result, "acvp/v1/algorithms"); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(result.Algorithms, "", " ")
|
||
|
return string(ret), err
|
||
|
}
|
||
|
|
||
|
type Env struct {
|
||
|
line string
|
||
|
variables map[string]Object
|
||
|
server *acvp.Server
|
||
|
term *terminal.Terminal
|
||
|
config Config
|
||
|
}
|
||
|
|
||
|
func (e *Env) bytes(node *node32) []byte {
|
||
|
return []byte(e.line[node.begin:node.end])
|
||
|
}
|
||
|
|
||
|
func (e *Env) contents(node *node32) string {
|
||
|
return e.line[node.begin:node.end]
|
||
|
}
|
||
|
|
||
|
type stringLiteral struct {
|
||
|
env *Env
|
||
|
contents string
|
||
|
}
|
||
|
|
||
|
func (s stringLiteral) String() (string, error) {
|
||
|
return s.contents, nil
|
||
|
}
|
||
|
|
||
|
func (stringLiteral) Index(_ string) (Object, error) {
|
||
|
return nil, errors.New("cannot index strings")
|
||
|
}
|
||
|
|
||
|
func (stringLiteral) Search(_ acvp.Query) (Object, error) {
|
||
|
return nil, errors.New("cannot search strings")
|
||
|
}
|
||
|
|
||
|
func (s stringLiteral) Action(action string, args []string) error {
|
||
|
switch action {
|
||
|
default:
|
||
|
return fmt.Errorf("action %q not supported on string literals", action)
|
||
|
|
||
|
case "GET":
|
||
|
if len(args) != 0 {
|
||
|
return fmt.Errorf("found %d arguments but %q takes none", len(args), action)
|
||
|
}
|
||
|
|
||
|
var results map[string]interface{}
|
||
|
if err := s.env.server.Get(&results, s.contents); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(results, "", " ")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
s.env.term.Write(ret)
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type results struct {
|
||
|
env *Env
|
||
|
prefix string
|
||
|
}
|
||
|
|
||
|
func (r results) String() (string, error) {
|
||
|
var results map[string]interface{}
|
||
|
if err := r.env.server.Get(&results, "acvp/v1/"+r.prefix+"/results"); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ret, err := json.MarshalIndent(results, "", " ")
|
||
|
return string(ret), err
|
||
|
}
|
||
|
|
||
|
func (results) Index(_ string) (Object, error) {
|
||
|
return nil, errors.New("cannot index results objects")
|
||
|
}
|
||
|
|
||
|
func (results) Search(_ acvp.Query) (Object, error) {
|
||
|
return nil, errors.New("cannot search results objects")
|
||
|
}
|
||
|
|
||
|
func (results) Action(_ string, _ []string) error {
|
||
|
return errors.New("no actions supported on results objects")
|
||
|
}
|
||
|
|
||
|
func (e *Env) parseStringLiteral(node *node32) string {
|
||
|
assertNodeType(node, ruleStringLiteral)
|
||
|
in := e.bytes(node)
|
||
|
var buf bytes.Buffer
|
||
|
for i := 1; i < len(in)-1; i++ {
|
||
|
if in[i] == '\\' {
|
||
|
switch in[i+1] {
|
||
|
case '\\':
|
||
|
buf.WriteByte('\\')
|
||
|
case 'n':
|
||
|
buf.WriteByte('\n')
|
||
|
case '"':
|
||
|
buf.WriteByte('"')
|
||
|
default:
|
||
|
panic("unknown escape")
|
||
|
}
|
||
|
i++
|
||
|
continue
|
||
|
}
|
||
|
buf.WriteByte(in[i])
|
||
|
}
|
||
|
|
||
|
return buf.String()
|
||
|
}
|
||
|
|
||
|
func (e *Env) evalExpression(node *node32) (obj Object, err error) {
|
||
|
switch node.pegRule {
|
||
|
case ruleStringLiteral:
|
||
|
return stringLiteral{e, e.parseStringLiteral(node)}, nil
|
||
|
|
||
|
case ruleVariable:
|
||
|
varName := e.contents(node)
|
||
|
obj, ok := e.variables[varName]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("unknown variable %q", varName)
|
||
|
}
|
||
|
return obj, nil
|
||
|
|
||
|
case ruleIndexing:
|
||
|
node = node.up
|
||
|
assertNodeType(node, ruleVariable)
|
||
|
varName := e.contents(node)
|
||
|
obj, ok := e.variables[varName]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("unknown variable %q", varName)
|
||
|
}
|
||
|
|
||
|
node = node.next
|
||
|
for node != nil {
|
||
|
assertNodeType(node, ruleIndex)
|
||
|
indexStr := e.contents(node)
|
||
|
if obj, err = obj.Index(indexStr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
node = node.next
|
||
|
}
|
||
|
|
||
|
return obj, nil
|
||
|
|
||
|
case ruleSearch:
|
||
|
node = node.up
|
||
|
assertNodeType(node, ruleVariable)
|
||
|
varName := e.contents(node)
|
||
|
obj, ok := e.variables[varName]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("unknown variable %q", varName)
|
||
|
}
|
||
|
|
||
|
node = skipWS(node.next)
|
||
|
assertNodeType(node, ruleQuery)
|
||
|
node = node.up
|
||
|
|
||
|
var query acvp.Query
|
||
|
for node != nil {
|
||
|
assertNodeType(node, ruleConjunctions)
|
||
|
query = append(query, e.parseConjunction(node.up))
|
||
|
node = skipWS(node.next)
|
||
|
}
|
||
|
|
||
|
if len(query) == 0 {
|
||
|
return nil, errors.New("cannot have empty query")
|
||
|
}
|
||
|
|
||
|
return obj.Search(query)
|
||
|
}
|
||
|
|
||
|
panic("unhandled")
|
||
|
}
|
||
|
|
||
|
func (e *Env) evalAction(node *node32) error {
|
||
|
assertNodeType(node, ruleExpression)
|
||
|
obj, err := e.evalExpression(node.up)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
node = node.next
|
||
|
assertNodeType(node, ruleCommand)
|
||
|
node = node.up
|
||
|
assertNodeType(node, ruleFunction)
|
||
|
function := e.contents(node)
|
||
|
node = node.next
|
||
|
|
||
|
var args []string
|
||
|
for node != nil {
|
||
|
assertNodeType(node, ruleArgs)
|
||
|
node = node.up
|
||
|
args = append(args, e.parseStringLiteral(node))
|
||
|
|
||
|
node = skipWS(node.next)
|
||
|
}
|
||
|
|
||
|
return obj.Action(function, args)
|
||
|
}
|
||
|
|
||
|
func (e *Env) parseConjunction(node *node32) (ret acvp.Conjunction) {
|
||
|
for node != nil {
|
||
|
assertNodeType(node, ruleConjunction)
|
||
|
ret = append(ret, e.parseCondition(node.up))
|
||
|
|
||
|
node = skipWS(node.next)
|
||
|
if node != nil {
|
||
|
assertNodeType(node, ruleConjunctions)
|
||
|
node = node.up
|
||
|
}
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (e *Env) parseCondition(node *node32) (ret acvp.Condition) {
|
||
|
assertNodeType(node, ruleField)
|
||
|
ret.Param = e.contents(node)
|
||
|
node = skipWS(node.next)
|
||
|
|
||
|
assertNodeType(node, ruleRelation)
|
||
|
switch e.contents(node) {
|
||
|
case "==":
|
||
|
ret.Relation = acvp.Equals
|
||
|
case "!=":
|
||
|
ret.Relation = acvp.NotEquals
|
||
|
case "contains":
|
||
|
ret.Relation = acvp.Contains
|
||
|
case "startsWith":
|
||
|
ret.Relation = acvp.StartsWith
|
||
|
case "endsWith":
|
||
|
ret.Relation = acvp.EndsWith
|
||
|
default:
|
||
|
panic("relation not handled: " + e.contents(node))
|
||
|
}
|
||
|
node = skipWS(node.next)
|
||
|
|
||
|
ret.Value = e.parseStringLiteral(node)
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func runInteractive(server *acvp.Server, config Config) {
|
||
|
oldState, err := terminal.MakeRaw(0)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
defer terminal.Restore(0, oldState)
|
||
|
term := terminal.NewTerminal(os.Stdin, "> ")
|
||
|
|
||
|
resizeChan := make(chan os.Signal)
|
||
|
go func() {
|
||
|
for _ = range resizeChan {
|
||
|
updateTerminalSize(term)
|
||
|
}
|
||
|
}()
|
||
|
signal.Notify(resizeChan, syscall.SIGWINCH)
|
||
|
|
||
|
env := &Env{variables: make(map[string]Object), server: server, term: term, config: config}
|
||
|
env.variables["requests"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "requests",
|
||
|
resultType: reflect.TypeOf(&acvp.RequestStatus{}),
|
||
|
canEnumerate: true,
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.8
|
||
|
env.variables["vendors"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "vendors",
|
||
|
searchKeys: map[string][]acvp.Relation{
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.8.1
|
||
|
"name": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"website": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"email": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"phoneNumber": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
},
|
||
|
subObjects: map[string]func(*Env, string) (Object, error){
|
||
|
"contacts": func(env *Env, prefix string) (Object, error) {
|
||
|
return ServerObjectSet{
|
||
|
env: env,
|
||
|
name: prefix + "/contacts",
|
||
|
resultType: reflect.TypeOf(&acvp.Person{}),
|
||
|
canEnumerate: true,
|
||
|
}, nil
|
||
|
},
|
||
|
"addresses": func(env *Env, prefix string) (Object, error) {
|
||
|
return ServerObjectSet{
|
||
|
env: env,
|
||
|
name: prefix + "/addresses",
|
||
|
resultType: reflect.TypeOf(&acvp.Address{}),
|
||
|
canEnumerate: true,
|
||
|
}, nil
|
||
|
},
|
||
|
},
|
||
|
resultType: reflect.TypeOf(&acvp.Vendor{}),
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.9
|
||
|
env.variables["persons"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "persons",
|
||
|
searchKeys: map[string][]acvp.Relation{
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.10.1
|
||
|
"fullName": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"email": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"phoneNumber": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"vendorId": []acvp.Relation{acvp.Equals, acvp.NotEquals, acvp.LessThan, acvp.LessThanEqual, acvp.GreaterThan, acvp.GreaterThanEqual},
|
||
|
},
|
||
|
resultType: reflect.TypeOf(&acvp.Person{}),
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.11
|
||
|
env.variables["modules"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "modules",
|
||
|
searchKeys: map[string][]acvp.Relation{
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.10.1
|
||
|
"name": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"version": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"website": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"description": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"type": []acvp.Relation{acvp.Equals, acvp.NotEquals},
|
||
|
"vendorId": []acvp.Relation{acvp.Equals, acvp.NotEquals, acvp.LessThan, acvp.LessThanEqual, acvp.GreaterThan, acvp.GreaterThanEqual},
|
||
|
},
|
||
|
resultType: reflect.TypeOf(&acvp.Module{}),
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.12
|
||
|
env.variables["oes"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "oes",
|
||
|
searchKeys: map[string][]acvp.Relation{
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.12.1
|
||
|
"name": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
},
|
||
|
resultType: reflect.TypeOf(&acvp.OperationalEnvironment{}),
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.13
|
||
|
env.variables["deps"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "dependencies",
|
||
|
searchKeys: map[string][]acvp.Relation{
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.12.1
|
||
|
"name": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"type": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
"description": []acvp.Relation{acvp.Equals, acvp.StartsWith, acvp.EndsWith, acvp.Contains},
|
||
|
},
|
||
|
resultType: reflect.TypeOf(&acvp.Dependency{}),
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.14
|
||
|
env.variables["algos"] = Algorithms{
|
||
|
ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "algorithms",
|
||
|
resultType: reflect.TypeOf(&acvp.Algorithm{}),
|
||
|
canEnumerate: true,
|
||
|
},
|
||
|
}
|
||
|
// https://usnistgov.github.io/ACVP/artifacts/draft-fussell-acvp-spec-00.html#rfc.section.11.15
|
||
|
env.variables["sessions"] = ServerObjectSet{
|
||
|
env: env,
|
||
|
name: "testSessions",
|
||
|
resultType: reflect.TypeOf(&acvp.TestSession{}),
|
||
|
canEnumerate: true,
|
||
|
subObjects: map[string]func(env *Env, prefix string) (Object, error){
|
||
|
"results": func(env *Env, prefix string) (Object, error) {
|
||
|
return results{env: env, prefix: prefix}, nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
if env.line, err = term.ReadLine(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(env.line) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
stmt := Statement{Buffer: env.line, Pretty: true}
|
||
|
stmt.Init()
|
||
|
if err := stmt.Parse(); err != nil {
|
||
|
io.WriteString(term, err.Error())
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
node := skipWS(stmt.AST().up)
|
||
|
switch node.pegRule {
|
||
|
case ruleExpression:
|
||
|
obj, err := env.evalExpression(node.up)
|
||
|
var repr string
|
||
|
if err == nil {
|
||
|
repr, err = obj.String()
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
fmt.Fprintf(term, "error while evaluating expression: %s\n", err)
|
||
|
} else {
|
||
|
io.WriteString(term, repr)
|
||
|
io.WriteString(term, "\n")
|
||
|
}
|
||
|
|
||
|
case ruleAction:
|
||
|
if err := env.evalAction(node.up); err != nil {
|
||
|
io.WriteString(term, err.Error())
|
||
|
io.WriteString(term, "\n")
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
fmt.Fprintf(term, "internal error parsing input.\n")
|
||
|
}
|
||
|
}
|
||
|
}
|