Konrad NeitzelandCursor 9e2005cfb3 Raise the module Go version to 1.27.0.
Match the Workspace pin so language and stdlib features through 1.27 are allowed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 17:16:16 +02:00
2026-09-20 17:16:16 +02:00

go-nc-exapp

Shared Go library for Nextcloud ExApp Services: AppAPI authentication, OCS JSON calls, per-user ExApp preferences, Notifications, Users and Groups, and an optional Required Groups Access Gate.

Import: gitea.neitzel.de/konrad/go-nc-exapp (package gonexapp).

Scope

Included

  • Credentials — Nextcloud base URL, AppAPI secret, and requesting user identity
  • AuthHeaders — outbound AppAPI authorization for OCS and other Nextcloud calls
  • WithUser — credentials scoped to a specific requesting user
  • UserFromRequest — extract the requesting user from inbound AppAPI-proxied requests
  • OCSClient — authenticated OCS calls that always append format=json
  • AppAPIPreferences — parameterized get/set of a string ExApp preference (caller supplies app id and key)
  • AppAPINotifications — Send (Recipient = Credentials user) and SendTo (explicit Recipient); Subject required; Message, Link, and rich-object params optional. AppAPI’s notification OCS is limited (no actions, no custom icon)
  • Groups — Users and Groups reads: UserGroups, GroupMembers, ListGroups (no search/paging). Directory calls (GroupMembers / ListGroups) run as the Credentials user and need an admin or subadmin
  • Access Gate — optional Required Groups enforcement (Wrap + Check), English denied HTML for browsers (200 + frame-ancestors 'self'), positive membership cache; default skip for lifecycle paths and /js/ top-menu scripts; env helpers for REQUIRED_GROUPS / REQUIRED_GROUPS_CACHE_SECONDS
  • Top Menu visibility — TopMenuAdminRequired helper for deploy env TOP_MENU_ADMIN_REQUIRED (0 / 1 for AppAPI top-menu OCS)

Excluded

  • ExApp lifecycle HTTP routes (/heartbeat, /enabled, …) — the Gate skips these by default but does not implement them
  • HaRP listen / serve() and unix-socket bootstrap
  • Top-menu, script, and iframe UI registration
  • WebDAV and file storage (see go-nc-files)
  • Visit folder resolution (see go-nc-files)
  • Fan-out Notifications (SendToGroup / SendToAdmins)
  • A Library default privileged / admin user for directory OCS (callers who need that use WithUser themselves)
  • CheckDNS (or any ExApp) wiring for Notifications or Groups — products opt in separately

Usage

cred := gonexapp.Credentials{
    BaseURL:    "https://nextcloud.example",
    AppID:      "myexapp",
    AppVersion: "0.1.0",
    AAVersion:  "1.0.0",
    AppSecret:  os.Getenv("APP_SECRET"),
    UserID:     "alice",
}

prefs := gonexapp.NewAppAPIPreferences(cred, "myexapp", "savedDefault")
value, err := prefs.Get()

err = gonexapp.NewAppAPINotifications(cred).Send(gonexapp.Notification{Subject: "Job finished"})
members, err := gonexapp.NewGroups(cred).GroupMembers("CheckDNS")

groupsEnv, groupsSet := os.LookupEnv("REQUIRED_GROUPS")
groups := gonexapp.ResolveRequiredGroups(groupsEnv, groupsSet, nil)
ttl := gonexapp.ParseCacheSeconds(os.Getenv("REQUIRED_GROUPS_CACHE_SECONDS"), gonexapp.DefaultCacheSeconds)
handler := gonexapp.AccessGate{Cred: cred, Groups: groups, CacheTTL: ttl}.Wrap(inner)

Each ExApp chooses its own preference keys; this library does not hardcode product-specific names.

Declare REQUIRED_GROUPS and REQUIRED_GROUPS_CACHE_SECONDS in the ExApp info.xml so Deploy options can set them.

The Gate skips /heartbeat, /enabled, /init, and any path under /js/ (AppAPI top-menu bootstrap). Serve the registered top-menu script under /js/… so a non-member still loads it and can show Denied UI in the Nextcloud shell. API routes stay gated.

Denied HTML is 200 with Content-Security-Policy: … frame-ancestors 'self'. Without that header AppAPI’s proxy defaults to frame-ancestors 'none' and a denied iframe stays blank. Non-HTML denials remain 403.

Top Menu visibility (TOP_MENU_ADMIN_REQUIRED)

Declare in info.xml under <environment-variables>. At enable time the ExApp reads the env and passes "0" or "1" to AppAPI’s top-menu OCS adminRequired. Only 0 and 1 are valid; anything else falls back to DefaultTopMenuAdminRequired (true → admins only).

adminRequired := gonexapp.TopMenuAdminRequired(
    os.Getenv(gonexapp.EnvTopMenuAdminRequired),
    gonexapp.DefaultTopMenuAdminRequired,
)
// use adminRequired in POST …/ui/top-menu when registering the menu entry

Applying a change: AppAPI registers the top menu when the ExApp receives PUT /enabled?enabled=1. Changing the deploy env alone does not update the menu entry.

  1. Set the new value in Deploy options (UI) or occ app_api:app:register … --env TOP_MENU_ADMIN_REQUIRED=… / update deploy config.
  2. Recreate or restart the ExApp container so the new env is present.
  3. Re-run lifecycle: disable then enable the ExApp (UI or occ app_api:app:disable / app_api:app:enable), or occ app_api:app:update … -e after an image/info update.

Route access_level in info.xml is separate and only changes when AppAPI re-reads info.xml on register/update — not via this env.

Runnable package examples: go test -run Example.

Domain language

See CONTEXT.md for AppAPI credentials, Requesting user, Recipient, ExApp preference, Notification, OCS, Required Groups, Users and Groups, Access Gate, and Top Menu visibility terminology.

Testing

Unit tests use httptest fake OCS servers. No live Nextcloud is required for Library CI.

  • go-nc-files — WebDAV, Working Folder, Saved Default, Visit resolution
  • Workspace ADR 0013 — extraction from CheckDNS
  • Workspace ADR docs/adr/go-nc-exapp/0001-required-groups-access-gate.md — Access Gate decisions
  • Workspace ADR docs/adr/go-nc-exapp/0002-users-and-groups-as-requesting-user.md — directory OCS as Requesting user
S
Description
Go module for nextcloud ExApps
Readme
172 KiB
Languages
Go 96.6%
JavaScript 3.4%