@appstrate/afps-shared 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appstrate/afps-shared",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Zero-dependency AFPS helpers shared by @appstrate/core and @appstrate/afps-runtime (companion-file checks, semver resolution, SRI integrity, credential templates, delivery.http projection)",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -96,3 +96,35 @@ export function projectHttpDeliveryConfig(
96
96
  }
97
97
  return cfg;
98
98
  }
99
+
100
+ /**
101
+ * Header names whose value is an RFC 9110 `credentials` production — an auth
102
+ * scheme token, one SP, then the credentials. Only in these positions is a
103
+ * bare token prefix a defect; anywhere else (`Cookie: session=`) it is an
104
+ * ordinary literal.
105
+ */
106
+ const AUTH_SCHEME_HEADERS = new Set(["authorization", "proxy-authorization"]);
107
+
108
+ /** RFC 9110 `token` grammar — matches a prefix that is nothing but a scheme. */
109
+ const BARE_AUTH_SCHEME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
110
+
111
+ /**
112
+ * True when `prefix` is nothing but an auth-scheme token AND `headerName` is a
113
+ * position whose value is an RFC 9110 `credentials` production.
114
+ *
115
+ * `prefix` is a LITERAL prepended to the rendered credential (AFPS §7.6), so a
116
+ * bare `"Bearer"` renders `Authorization: BearerTOKEN` — a malformed credential
117
+ * every upstream answers with a 401 that names nothing. The injector
118
+ * (`@appstrate/afps-runtime`'s `planHttpDeliveryInjection`) concatenates
119
+ * verbatim and repairs nothing, so every path that accepts an author-written
120
+ * prefix must refuse the bare form up front instead. This is the one grammar
121
+ * those gates share: the integration manifest validator
122
+ * (`@appstrate/core/integration`, install time) and the portable runtime's
123
+ * local creds file (`resolvers/integration-api-call.ts`, load time).
124
+ *
125
+ * Callers pass the EFFECTIVE header name — the one that will actually be sent,
126
+ * after their own defaulting has been applied.
127
+ */
128
+ export function isBareAuthSchemePrefix(headerName: string, prefix: string): boolean {
129
+ return AUTH_SCHEME_HEADERS.has(headerName.toLowerCase()) && BARE_AUTH_SCHEME.test(prefix);
130
+ }
@@ -80,7 +80,7 @@ export interface GuardedFetchOptions {
80
80
  fetchImpl?: typeof fetch;
81
81
  /**
82
82
  * Opt-in predicate for hosts the OPERATOR has explicitly trusted (e.g. an
83
- * internal IdP on a private address via `OAUTH_ALLOWED_INTERNAL_IDP_HOSTS`).
83
+ * internal IdP on a private address via `EGRESS_ALLOW_INTERNAL_HOSTS`).
84
84
  * When it returns true the host blocklist is skipped for that hop, but the
85
85
  * manual-redirect discipline (cross-origin body/credential stripping) still
86
86
  * applies — so a trusted host that open-redirects cannot forward the secret.