key and API address fall back to the person's secrets file; a non-git folder becomes a local_path project

This commit is contained in:
Sam
2026-11-12 17:19:37 +11:00
parent 3043e9dec1
commit 55085ba40a
11 changed files with 766 additions and 15 deletions

View File

@@ -13,6 +13,7 @@ import (
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
@@ -29,21 +30,79 @@ type Client struct {
//
// The token is read from PAPERCLIP_BOARD_KEY (the person's key) and only falls
// back to PAPERCLIP_API_KEY for read-only use. The token is never logged.
// fromSecrets reads one variable out of the person's own secrets file, for the
// same reason as the shell fallback: a terminal started by a desktop session
// does not inherit systemd's environment.d. The file is the person's; this
// only reads it, and the value is never logged.
func fromSecrets(name string) string {
home, err := os.UserHomeDir()
if err != nil {
return ""
}
dir := filepath.Join(home, ".config", "environment.d")
entries, err := os.ReadDir(dir)
if err != nil {
return ""
}
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".conf") {
continue
}
data, err := os.ReadFile(filepath.Join(dir, e.Name()))
if err != nil {
continue
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
k, v, ok := strings.Cut(line, "=")
if ok && strings.TrimSpace(k) == name {
return strings.Trim(strings.TrimSpace(v), `"'`)
}
}
}
return ""
}
func varOr(name, fallback string) string {
if v := os.Getenv(name); v != "" {
return v
}
if v := fromSecrets(name); v != "" {
return v
}
return fallback
}
// reachable says whether something answers at this address right now.
func reachable(url string) bool {
c := &http.Client{Timeout: 2 * time.Second}
resp, err := c.Get(url)
if err != nil {
return false
}
resp.Body.Close()
return resp.StatusCode == 200
}
func New() (*Client, error) {
base := os.Getenv("PAPERCLIP_API_URL")
base := varOr("PAPERCLIP_API_URL", "")
if base == "" {
base = "http://127.0.0.1:3100"
if !reachable(base + "/api/health") {
// Paperclip lives on one machine; a session on another has to ask it.
base = "http://192.168.20.13:3100"
}
}
company := os.Getenv("PAPERCLIP_COMPANY_ID")
if company == "" {
company = "d4921013-e5da-4d88-8016-57d5746e2d03"
}
token := os.Getenv("PAPERCLIP_BOARD_KEY")
company := varOr("PAPERCLIP_COMPANY_ID", "d4921013-e5da-4d88-8016-57d5746e2d03")
token := varOr("PAPERCLIP_BOARD_KEY", "")
if token == "" {
token = os.Getenv("PAPERCLIP_API_KEY")
token = varOr("PAPERCLIP_API_KEY", "")
}
if token == "" {
return nil, errors.New("no key in the environment: set PAPERCLIP_BOARD_KEY")
return nil, errors.New("no key found: set PAPERCLIP_BOARD_KEY, or put it in ~/.config/environment.d/*.conf")
}
return &Client{
BaseURL: strings.TrimRight(base, "/"),