Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactoring: testifysec/archivista-api as a pkg #120

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/archivistactl/cmd/retrieve.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"strings"

"github.com/spf13/cobra"
archivistaapi "github.com/testifysec/archivista-api"
"github.com/testifysec/archivista/pkg/api"
)

var (
Expand Down Expand Up @@ -50,7 +50,7 @@ var (
out = file
}

return archivistaapi.DownloadWithWriter(cmd.Context(), archivistaUrl, args[0], out)
return api.DownloadWithWriter(cmd.Context(), archivistaUrl, args[0], out)
},
}

Expand All @@ -60,7 +60,7 @@ var (
SilenceUsage: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
results, err := archivistaapi.GraphQlQuery[retrieveSubjectResults](cmd.Context(), archivistaUrl, retrieveSubjectsQuery, retrieveSubjectVars{Gitoid: args[0]})
results, err := api.GraphQlQuery[retrieveSubjectResults](cmd.Context(), archivistaUrl, retrieveSubjectsQuery, retrieveSubjectVars{Gitoid: args[0]})
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/archivistactl/cmd/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"strings"

"github.com/spf13/cobra"
archivistaapi "github.com/testifysec/archivista-api"
"github.com/testifysec/archivista/pkg/api"
)

var (
Expand Down Expand Up @@ -49,7 +49,7 @@ Digests are expected to be in the form algorithm:digest, for instance: sha256:45
return err
}

results, err := archivistaapi.GraphQlQuery[searchResults](cmd.Context(), archivistaUrl, searchQuery, searchVars{Algorithm: algo, Digest: digest})
results, err := api.GraphQlQuery[searchResults](cmd.Context(), archivistaUrl, searchQuery, searchVars{Algorithm: algo, Digest: digest})
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/archivistactl/cmd/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"os"

"github.com/spf13/cobra"
archivistaapi "github.com/testifysec/archivista-api"
"github.com/testifysec/archivista/pkg/api"
)

var (
Expand Down Expand Up @@ -54,7 +54,7 @@ func storeAttestationByPath(ctx context.Context, baseUrl, path string) (string,
}

defer file.Close()
resp, err := archivistaapi.StoreWithReader(ctx, baseUrl, file)
resp, err := api.StoreWithReader(ctx, baseUrl, file)
if err != nil {
return "", err
}
Expand Down
14 changes: 7 additions & 7 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"github.com/edwarnicke/gitoid"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
archivistaapi "github.com/testifysec/archivista-api"
"github.com/testifysec/archivista/pkg/api"
)

type Server struct {
Expand All @@ -52,31 +52,31 @@ func New(metadataStore Storer, objectStore StorerGetter) *Server {
return &Server{metadataStore, objectStore}
}

func (s *Server) Store(ctx context.Context, r io.Reader) (archivistaapi.StoreResponse, error) {
func (s *Server) Store(ctx context.Context, r io.Reader) (api.StoreResponse, error) {
payload, err := io.ReadAll(r)
if err != nil {
return archivistaapi.StoreResponse{}, err
return api.StoreResponse{}, err
}

gid, err := gitoid.New(bytes.NewReader(payload), gitoid.WithContentLength(int64(len(payload))), gitoid.WithSha256())
if err != nil {
logrus.Errorf("failed to generate gitoid: %v", err)
return archivistaapi.StoreResponse{}, err
return api.StoreResponse{}, err
}

if err := s.metadataStore.Store(ctx, gid.String(), payload); err != nil {
logrus.Errorf("received error from metadata store: %+v", err)
return archivistaapi.StoreResponse{}, err
return api.StoreResponse{}, err
}

if s.objectStore != nil {
if err := s.objectStore.Store(ctx, gid.String(), payload); err != nil {
logrus.Errorf("received error from object store: %+v", err)
return archivistaapi.StoreResponse{}, err
return api.StoreResponse{}, err
}
}

return archivistaapi.StoreResponse{Gitoid: gid.String()}, nil
return api.StoreResponse{Gitoid: gid.String()}, nil
}

func (s *Server) StoreHandler(w http.ResponseWriter, r *http.Request) {
Expand Down
74 changes: 74 additions & 0 deletions pkg/api/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2023 The Witness Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/url"

"github.com/testifysec/go-witness/dsse"
)

func Download(ctx context.Context, baseUrl string, gitoid string) (dsse.Envelope, error) {
buf := &bytes.Buffer{}
if err := DownloadWithWriter(ctx, baseUrl, gitoid, buf); err != nil {
return dsse.Envelope{}, err
}

env := dsse.Envelope{}
dec := json.NewDecoder(buf)
if err := dec.Decode(&env); err != nil {
return env, err
}

return env, nil
}

func DownloadWithWriter(ctx context.Context, baseUrl, gitoid string, dst io.Writer) error {
downloadUrl, err := url.JoinPath(baseUrl, "download", gitoid)
if err != nil {
return err
}

req, err := http.NewRequestWithContext(ctx, "GET", downloadUrl, nil)
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/json")
hc := &http.Client{}
resp, err := hc.Do(req)
if err != nil {
return nil
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errMsg, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

return errors.New(string(errMsg))
}

_, err = io.Copy(dst, resp.Body)
return err
}
92 changes: 92 additions & 0 deletions pkg/api/graphql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2023 The Witness Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
)

type graphQLError struct {
Message string `json:"message"`
}

type graphQLResponse[T any] struct {
Data T `json:"data,omitempty"`
Errors []graphQLError `json:"errors,omitempty"`
}

type graphQLRequestBody[TVars any] struct {
Query string `json:"query"`
Variables TVars `json:"variables,omitempty"`
}

func GraphQlQuery[TRes any, TVars any](ctx context.Context, baseUrl, query string, vars TVars) (TRes, error) {
var response TRes
queryUrl, err := url.JoinPath(baseUrl, "query")
if err != nil {
return response, err
}

requestBody := graphQLRequestBody[TVars]{
Query: query,
Variables: vars,
}

reqBody, err := json.Marshal(requestBody)
if err != nil {
return response, err
}

req, err := http.NewRequestWithContext(ctx, "POST", queryUrl, bytes.NewReader(reqBody))
if err != nil {
return response, err
}

req.Header.Set("Content-Type", "application/json")
hc := &http.Client{}
res, err := hc.Do(req)
if err != nil {
return response, err
}

defer res.Body.Close()
if res.StatusCode != http.StatusOK {
errMsg, err := io.ReadAll(res.Body)
if err != nil {
return response, err
}

return response, errors.New(string(errMsg))
}

dec := json.NewDecoder(res.Body)
gqlRes := graphQLResponse[TRes]{}
if err := dec.Decode(&gqlRes); err != nil {
return response, err
}

if len(gqlRes.Errors) > 0 {
return response, fmt.Errorf("graph ql query failed: %v", gqlRes.Errors)
}

return gqlRes.Data, nil
}
77 changes: 77 additions & 0 deletions pkg/api/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2023 The Witness Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/url"

"github.com/testifysec/go-witness/dsse"
)

type StoreResponse struct {
Gitoid string `json:"gitoid"`
}

func Store(ctx context.Context, baseUrl string, envelope dsse.Envelope) (StoreResponse, error) {
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
if err := enc.Encode(envelope); err != nil {
return StoreResponse{}, err
}

return StoreWithReader(ctx, baseUrl, buf)
}

func StoreWithReader(ctx context.Context, baseUrl string, r io.Reader) (StoreResponse, error) {
uploadPath, err := url.JoinPath(baseUrl, "upload")
if err != nil {
return StoreResponse{}, err
}

req, err := http.NewRequestWithContext(ctx, "POST", uploadPath, r)
if err != nil {
return StoreResponse{}, err
}

req.Header.Set("Content-Type", "application/json")
hc := &http.Client{}
resp, err := hc.Do(req)
if err != nil {
return StoreResponse{}, err
}

defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return StoreResponse{}, err
}

if resp.StatusCode != http.StatusOK {
return StoreResponse{}, errors.New(string(bodyBytes))
}

storeResp := StoreResponse{}
if err := json.Unmarshal(bodyBytes, &storeResp); err != nil {
return StoreResponse{}, err
}

return storeResp, nil
}