internal/api/api.go (65 lines of code) (raw):
package internal_api //nolint:staticcheck
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
"gitlab.com/gitlab-org/gitlab-zoekt-indexer/internal/authentication"
)
const (
apiBasePath = "/api/v4/internal/search/zoekt"
jwtIssuer = "gitlab-shell" // Needs to be shell so that rails verifies the payload
jwtRequestHeader = "Gitlab-Shell-Api-Request" // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/426557
jwtTTL = time.Minute
)
type InternalAPIRequestParams struct {
Path string
BodyParams any
GitlabURL string
NodeUUID string
Secret []byte
}
func NewRequest(ctx context.Context, params InternalAPIRequestParams) (*http.Request, error) {
if len(params.Secret) == 0 {
return nil, fmt.Errorf("secret is empty")
}
secret, err := generateJWTForRailsAPI(params.Secret)
if err != nil {
return nil, err
}
endpoint, err := url.JoinPath(params.GitlabURL, apiBasePath, params.NodeUUID, params.Path)
if err != nil {
return nil, err
}
var body io.Reader
if params.BodyParams != nil {
jsonParams, marshalErr := json.Marshal(params.BodyParams)
if marshalErr != nil {
return nil, marshalErr
}
body = bytes.NewReader(jsonParams)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
if err != nil {
return nil, err
}
req.Header = http.Header{
"Accept": []string{"application/json"},
jwtRequestHeader: []string{secret},
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
return req, nil
}
func generateJWTForRailsAPI(secret []byte) (string, error) {
tokenString, authErr := authentication.NewAuth(jwtIssuer, jwtTTL, secret).GenerateJWT()
if authErr != nil {
return "", authErr
}
return tokenString, nil
}