forked from TrueCloudLab/lego
Vitaliy Potyarkin
597d147c7d
Current reverse proxy configs assume that token is a valid filename with no nesting levels. It's better to reject unsupported tokens early Signed-off-by: Vitaliy Potyarkin <v.potyarkin@yadro.com>
85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
// Package frostfs provides HTTP-01 solver that saves challenge token to
|
|
// FrostFS to make it available to multiple hosts at once.
|
|
// Useful for deploying FrostFS gateways (HTTP or S3)
|
|
package frostfs
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-acme/lego/v4/challenge"
|
|
)
|
|
|
|
const (
|
|
// Challenge token will be garbage collected sometime after this interval
|
|
// even if Cleanup() call fails for whatever reason.
|
|
tokenLifetime = 1 * time.Hour
|
|
)
|
|
|
|
// HTTPProvider is a custom solver for HTTP-01 challenge that saves token to FrostFS.
|
|
type HTTPProvider struct {
|
|
frostfs *Storage
|
|
oid string
|
|
}
|
|
|
|
var _ challenge.Provider = new(HTTPProvider)
|
|
|
|
func NewHTTPProvider(endpoint, cid, walletPath, walletAccount, walletPassword string) (*HTTPProvider, error) {
|
|
if endpoint == "" {
|
|
return nil, errors.New("empty endpoint")
|
|
}
|
|
if cid == "" {
|
|
return nil, errors.New("empty container id")
|
|
}
|
|
key, err := getKey(walletPath, walletAccount, walletPassword)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
storage, err := Open(endpoint, cid, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &HTTPProvider{frostfs: storage}, nil
|
|
}
|
|
|
|
func (w *HTTPProvider) Present(domain, token, keyAuth string) error {
|
|
if strings.Contains(token, "/") {
|
|
return fmt.Errorf("token with slash character is not supported: %s", token)
|
|
}
|
|
if w.oid != "" {
|
|
return fmt.Errorf("%T is not safe to re-enter: object was saved and not yet cleaned up: %s", w, w.oid)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
var err error
|
|
expires, err := w.frostfs.Epoch(ctx, time.Now().Add(tokenLifetime))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to calculate token expiration: %w", err)
|
|
}
|
|
w.oid, err = w.frostfs.Save(
|
|
ctx,
|
|
[]byte(keyAuth),
|
|
"FileName", token,
|
|
"ACME", token,
|
|
"__SYSTEM__EXPIRATION_EPOCH", strconv.FormatUint(expires, 10),
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (w *HTTPProvider) CleanUp(domain, token, keyAuth string) error {
|
|
if w.oid == "" {
|
|
panic("Cleanup() called before Present()")
|
|
}
|
|
err := w.frostfs.Delete(context.TODO(), w.oid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.oid = ""
|
|
return nil
|
|
}
|