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 }