Publish gonexapp v1 with Credentials, OCSClient, and parameterized AppAPIPreferences so ExApps share Nextcloud ExApp plumbing per ADR 0013. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
package gonexapp
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// Credentials are what an ExApp needs to call Nextcloud as a user.
|
|
type Credentials struct {
|
|
BaseURL string // Nextcloud instance URL, no trailing slash
|
|
AppID string
|
|
AppVersion string
|
|
AAVersion string
|
|
AppSecret string
|
|
UserID string
|
|
}
|
|
|
|
// AuthHeaders returns AppAPI auth headers for requests to Nextcloud.
|
|
func (c Credentials) AuthHeaders() http.Header {
|
|
h := make(http.Header)
|
|
h.Set("AA-VERSION", c.AAVersion)
|
|
h.Set("EX-APP-ID", c.AppID)
|
|
h.Set("EX-APP-VERSION", c.AppVersion)
|
|
token := base64.StdEncoding.EncodeToString([]byte(c.UserID + ":" + c.AppSecret))
|
|
h.Set("AUTHORIZATION-APP-API", token)
|
|
h.Set("OCS-APIRequest", "true")
|
|
return h
|
|
}
|
|
|
|
// WithUser returns a copy acting as userID.
|
|
func (c Credentials) WithUser(userID string) Credentials {
|
|
out := c
|
|
out.UserID = userID
|
|
return out
|
|
}
|
|
|
|
// UserFromRequest reads the requesting user from AUTHORIZATION-APP-API on an inbound ExApp request.
|
|
func UserFromRequest(r *http.Request) (string, error) {
|
|
raw := r.Header.Get("AUTHORIZATION-APP-API")
|
|
if raw == "" {
|
|
return "", fmt.Errorf("missing AUTHORIZATION-APP-API")
|
|
}
|
|
decoded, err := base64.StdEncoding.DecodeString(raw)
|
|
if err != nil {
|
|
return "", fmt.Errorf("invalid AUTHORIZATION-APP-API: %w", err)
|
|
}
|
|
parts := strings.SplitN(string(decoded), ":", 2)
|
|
if len(parts) < 1 || strings.TrimSpace(parts[0]) == "" {
|
|
return "", fmt.Errorf("AUTHORIZATION-APP-API has no user id")
|
|
}
|
|
return parts[0], nil
|
|
}
|