Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ All notable changes to the `stream-connect-sdk` npm package. The
companion React Native hook (`stream-connect-sdk-hook`) is on its own
release line; see [`sdk-hook/docs/README.md`](./sdk-hook/docs/README.md).

## 0.8.2

### Refuse to initialize on insecure (plain HTTP) host pages

`StreamConnect()` now checks `window.isSecureContext` at init and
refuses to mount the SDK if the host page is served over plain HTTP
from a non-loopback host. The browser-level secure-context check is
true on HTTPS and on the loopback hosts (`localhost`, `127.0.0.1`,
`[::1]`) — same set the new server-side CORS policy allows — so
local development against `vite`, `webpack-dev-server`, etc. is
unaffected.

The previous behavior on a plain-HTTP page was a generic
CORS-blocked error in the browser console on the first
`/sdk-api/*` request, with no actionable explanation. The SDK now
fails fast with a clear console error, calls the optional
`handleInitErrors` callback with the same message, and links to
the [origin-policy docs](https://developers.tpastream.com/connect/origin-policy)
explaining the requirement and how to fix it.

Members were never charged the network round-trip on a broken
plain-HTTP integration in the first place, so the practical effect
is shifting the error from "browser console mystery" to "init-time
diagnostic that names the problem."

## 0.8.1

### Handle expired connectAccessToken without a confusing error
Expand Down
35 changes: 34 additions & 1 deletion assets/sdk/entries/sdk-core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@ import type { SDKInitOptions } from '../types-init';
// stylesheet so customers driving their own UI via the renderXxx
// callbacks aren't forced to ship our ~50 KB of Tailwind output.

const VERSION = '0.8.1';
const VERSION = '0.8.2';

const ORIGIN_POLICY_DOCS_URL =
'https://developers.tpastream.com/connect/origin-policy';

// `window.isSecureContext` is the W3C primitive browsers use to gate
// any API that handles sensitive data (WebAuthn, getUserMedia, service
// workers). It is true on HTTPS pages and on the loopback hosts the
// browser treats as secure — `localhost`, `127.0.0.1`, `[::1]`, file://,
// chrome-extension:// — and false for plain `http://` everywhere else.
//
// We mirror that on the server (stream/security/sdk_cors.py) — the
// `/sdk-api/*` CORS regex only echoes Access-Control-Allow-Origin for
// HTTPS or loopback HTTP. So an integration loaded into a plain-HTTP
// host page would hit a generic browser CORS-blocked error on the very
// first API call, with no actionable explanation. Catch it here at
// init() instead and report it clearly to the console + handleInitErrors
// so the developer goes straight to the docs.
const isSecureSDKContext = (): boolean => {
// SSR / non-browser harnesses (Jest with jsdom unset, etc.) can't
// be evaluated — fall through, the later `document.querySelector`
// path errors with its own message.
if (typeof window === 'undefined') return true;
return window.isSecureContext;
};

// Track one React root per container element. Some host pages call
// StreamConnect() more than once against the same `el` (e.g. on a
Expand Down Expand Up @@ -181,6 +205,15 @@ const StreamConnect = (options: SDKInitOptions) => {
return;
}

if (!isSecureSDKContext()) {
const origin =
typeof window !== 'undefined' ? window.location.origin : '(unknown)';
const msg = `[stream-connect-sdk] init failed: host page must be served over HTTPS (or from http://localhost, http://127.0.0.1, or http://[::1] for local development). The current page origin ${origin} is insecure, and the SDK transmits member credentials — sending those over plain HTTP would expose them in transit. See ${ORIGIN_POLICY_DOCS_URL} for the fix.`;
console.error(msg);
options.handleInitErrors?.(new Error(msg));
return;
}

console.log(`TPAStream Connect SDK v${VERSION}`);

const normalized = normalizeOptions(options);
Expand Down
6 changes: 6 additions & 0 deletions docs/migration-0.7-to-0.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ If you deliberately want the legacy fallthrough behavior — e.g. you're doing c

If you use `renderChoosePayer={false}` / `renderPayerForm={false}` / `renderEndWidget={false}` and drive those steps from `doneChoosePayer` / `doneCreatedForm` / `doneEasyEnroll`, the data passed into your callbacks is unchanged.

### 9. Host page must be HTTPS (0.8.2)

Starting in 0.8.2, `StreamConnect()` refuses to mount if the host page is served over plain `http://` from a non-loopback host. `localhost`, `127.0.0.1`, and `[::1]` are still allowed so local development is unaffected. Staging or internal hostnames served over plain HTTP are not.

If you embed the SDK in a member-facing page that's currently on plain HTTP, that page must move to HTTPS before 0.8.x will mount. See the [Origin Policy doc](https://developers.tpastream.com/connect/origin-policy) for the full rules, the exact console error developers will see, and how to fix it.

## What you do NOT need to do

- You do not need to add a `theme` option. The default appearance applies automatically.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stream-connect-sdk",
"version": "0.8.1",
"version": "0.8.2",
"description": "A JavaScript SDK implementing TPAStream's Connect Platform",
"scripts": {
"build": "webpack --config webpack.prod-sdk.js --mode=production",
Expand Down
Loading