mirror of
https://github.com/wassname/talk.git
synced 2026-07-05 07:56:57 +08:00
Merge pull request #921 from coralproject/change-websocket-uri
Change Websocket URI
This commit is contained in:
+36
-2
@@ -15,6 +15,25 @@ import globalFragments from 'coral-framework/graphql/fragments';
|
||||
import {createStorage} from 'coral-framework/services/storage';
|
||||
import {createHistory} from 'coral-framework/services/history';
|
||||
|
||||
/**
|
||||
* getStaticConfiguration will return a singleton of the static configuration
|
||||
* object provided via a JSON DOM element.
|
||||
*/
|
||||
const getStaticConfiguration = (() => {
|
||||
let staticConfiguration = null;
|
||||
return () => {
|
||||
if (staticConfiguration != null) {
|
||||
return staticConfiguration;
|
||||
}
|
||||
|
||||
const configElement = document.querySelector('#data');
|
||||
|
||||
staticConfiguration = JSON.parse(configElement ? configElement.textContent : '{}');
|
||||
|
||||
return staticConfiguration;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* getAuthToken returns the active auth token or null
|
||||
* Note: this method does not have access to the cookie based token used by
|
||||
@@ -49,7 +68,6 @@ const getAuthToken = (store, storage) => {
|
||||
* @return {Object} context
|
||||
*/
|
||||
export function createContext({reducers = {}, pluginsConfig = [], graphqlExtension = {}, notification} = {}) {
|
||||
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const eventEmitter = new EventEmitter({wildcard: true});
|
||||
const storage = createStorage();
|
||||
const history = createHistory(BASE_PATH);
|
||||
@@ -63,13 +81,28 @@ export function createContext({reducers = {}, pluginsConfig = [], graphqlExtensi
|
||||
// TOKEN YOU MUST DISCONNECT AND RECONNECT THE WEBSOCKET CLIENT.
|
||||
return getAuthToken(store, storage);
|
||||
};
|
||||
|
||||
const rest = createRestClient({
|
||||
uri: `${BASE_PATH}api/v1`,
|
||||
token,
|
||||
});
|
||||
|
||||
// Try to get an overrided liveUri from the static config, if none is found,
|
||||
// build it.
|
||||
let {LIVE_URI: liveUri} = getStaticConfiguration();
|
||||
if (liveUri == null) {
|
||||
|
||||
// The protocol must match the origin protocol, secure/insecure.
|
||||
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
|
||||
// Compose the live url from this protocol, the current host + base path
|
||||
// with the live path appended to it.
|
||||
liveUri = `${protocol}://${location.host}${BASE_PATH}api/v1/live`;
|
||||
}
|
||||
|
||||
const client = createClient({
|
||||
uri: `${BASE_PATH}api/v1/graph/ql`,
|
||||
liveUri: `${protocol}://${location.host}${BASE_PATH}api/v1/live`,
|
||||
liveUri,
|
||||
token,
|
||||
});
|
||||
const plugins = createPluginsService(pluginsConfig);
|
||||
@@ -79,6 +112,7 @@ export function createContext({reducers = {}, pluginsConfig = [], graphqlExtensi
|
||||
// Use default notification service (pym based)
|
||||
notification = createNotificationService(pym);
|
||||
}
|
||||
|
||||
const context = {
|
||||
client,
|
||||
pym,
|
||||
|
||||
@@ -135,6 +135,9 @@ const CONFIG = {
|
||||
RECAPTCHA_PUBLIC: process.env.TALK_RECAPTCHA_PUBLIC,
|
||||
RECAPTCHA_SECRET: process.env.TALK_RECAPTCHA_SECRET,
|
||||
|
||||
// WEBSOCKET_LIVE_URI is the absolute url to the live endpoint.
|
||||
WEBSOCKET_LIVE_URI: process.env.TALK_WEBSOCKET_LIVE_URI || null,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SMTP Server configuration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -38,6 +38,8 @@ docs:
|
||||
url: /docs/running/plugins/
|
||||
- title: "Database Migrations"
|
||||
url: /docs/running/migrations/
|
||||
- title: "Persistence"
|
||||
url: /docs/running/persistence/
|
||||
- title: "Architecture"
|
||||
url: /docs/architecture/
|
||||
children:
|
||||
|
||||
@@ -91,7 +91,7 @@ source process), then:
|
||||
|
||||
```
|
||||
cd docs
|
||||
docker run --rm --volume=$PWD:/srv/jekyll -p 127.0.0.1:4000:4000 -it jekyll/jekyll:pages jekyll serve
|
||||
docker run --rm --volume=$PWD:/srv/jekyll -p 127.0.0.1:4000:4000 -it jekyll/jekyll:pages bash -c "bundle install && jekyll serve"
|
||||
```
|
||||
|
||||
You can edit the files in docs with any editor and view the live updates in a
|
||||
|
||||
@@ -53,6 +53,7 @@ These are only used during the webpack build.
|
||||
- `TALK_REDIS_URL` (*required*) - the database connection string for the Redis database.
|
||||
|
||||
#### Advanced
|
||||
{:.no_toc}
|
||||
|
||||
- `TALK_REDIS_RECONNECTION_MAX_ATTEMPTS` (_optional_) - the amount of attempts
|
||||
that a redis connection will attempt to reconnect before aborting with an
|
||||
@@ -76,11 +77,19 @@ These are only used during the webpack build.
|
||||
- `TALK_INSTALL_LOCK` (_optional for dynamic setup_) - When `TRUE`, disables the dynamic setup endpoint. (Default `FALSE`)
|
||||
|
||||
#### Advanced
|
||||
{:.no_toc}
|
||||
|
||||
- `TALK_ROOT_URL_MOUNT_PATH` (_optional_) - when set to `TRUE`, the routes will
|
||||
be mounted onto the `<pathname>` component of the `TALK_ROOT_URL`. You would
|
||||
use this when your upstream proxy cannot strip the prefix from the url.
|
||||
(Default `FALSE`)
|
||||
- `TALK_WEBSOCKET_LIVE_URI` (_optional_) - used to override the location to
|
||||
connect to the websocket endpoint to potentially another host. This should
|
||||
be used when you need to route websocket requests out of your CDN in order to
|
||||
serve traffic more efficiently for websockets. **Warning: if used without
|
||||
managing the auth state manually, auth cannot be persisted, for further
|
||||
information refer to the [Persistence Documentation]({{ "/docs/running/persistence/" | absolute_url }})**
|
||||
(Default `${ssl ? 'ws' : 'wss'}://${location.host}${TALK_ROOT_URL_MOUNT_PATH}api/v1/live`)
|
||||
|
||||
### Word Filter
|
||||
|
||||
@@ -105,6 +114,7 @@ variable. Refer to the [Secrets Documentation]({{ "/docs/running/secrets/" | abs
|
||||
on the contents of those variables.**
|
||||
|
||||
#### Advanced
|
||||
{:.no_toc}
|
||||
|
||||
These are advanced settings for fine tuning the auth integration, and
|
||||
is not needed in most situations.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: User Persistence
|
||||
permalink: /docs/running/persistence/
|
||||
---
|
||||
|
||||
One of the biggest problems on the internet today is the proliferation of
|
||||
sophisticated tracking systems and the outcome of invading user's privacy. This
|
||||
has had quite a big impact on our design of Talk, as we've had to work around
|
||||
the safeguards that are there to keep your data safe while still allowing our
|
||||
application to run smoothly on the page it's embedded on.
|
||||
|
||||
---
|
||||
|
||||
**Problem**: Safari has inconsistent behavior around localStorage when used
|
||||
within an iFrame.
|
||||
|
||||
**Solution**: We set a cookie instead when Safari is detected to store the auth
|
||||
state.
|
||||
|
||||
---
|
||||
|
||||
**Problem**: Safari's default privacy settings block cookies from domains that
|
||||
do not match the current domain.
|
||||
|
||||
**Solution**: When using Talk's built in auth, we will open a pop-out when
|
||||
setting the cookie, so that the domain of the setting domain matches the issuer.
|
||||
|
||||
---
|
||||
|
||||
**Problem**: When using a different domain for websockets, and using the built
|
||||
in auth solution, cookies are not set on that domain for use with Safari.
|
||||
|
||||
**No Solution Exists**: It is our expectation that for users that must deploy
|
||||
Talk in environments that must run the websockets out of a separate domain will
|
||||
use and integrate their own auth solution. During the login process in Talk,
|
||||
users submit their user credentials to an auth endpoint, and receive a token
|
||||
back, or for Safari, a cookie. Aggressive defaults in Safari make it not
|
||||
possible to have one domain set cookies for another domain during this process.
|
||||
This results in a situation where we have no way to persist the auth credentials
|
||||
for this specific situation for the time being.
|
||||
|
||||
---
|
||||
|
||||
If you are using a custom auth solution, (Which involves providing the user's
|
||||
jwt token via the `auth_token` parameter on the call to
|
||||
`Talk.render(... {auth_token})` and creating the
|
||||
[tokenUserNotFound]({{ "/docs/plugins/server/" | absolute_url }}) hook to lookup
|
||||
that user) then concerns related to cookies/localStorage are moot! As it isn't
|
||||
necessary for Talk to maintain any state beyond what is passed to it via the
|
||||
pym bridge.
|
||||
@@ -85,7 +85,7 @@ configure the context plugin before it would be mounted at `context.plugins`.
|
||||
This plugin above would mount at: `context.plugins.Slack`, or, if you're using
|
||||
[object destructuring](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), `{plugins: {Slack}}`.
|
||||
|
||||
##### `Sort`
|
||||
##### Field: `Sort`
|
||||
|
||||
A special context hook, `Sort` will allow plugin authors to provide new
|
||||
methods to sort data. An example is as follows:
|
||||
@@ -269,22 +269,6 @@ The function is async, and should return the user object that was created in the
|
||||
database, or null if the user wasn't found. The `jwt` parameter of the object
|
||||
is the unpacked token, while `token` is the original jwt token string.
|
||||
|
||||
### Routes
|
||||
|
||||
#### Field: `router`
|
||||
|
||||
```js
|
||||
(router) => {
|
||||
router.get('/api/v1/people', (req, res) => {
|
||||
res.json({people: [{name: 'Bob'}]});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The Router hook allows you to create a function that accepts the base express
|
||||
router where you can mount any amount of middleware/routes to do any form of
|
||||
action needed by external applications.
|
||||
|
||||
#### Field: `tags`
|
||||
|
||||
The tags hook allows a plugin to define tags that are code controlled (added
|
||||
@@ -309,6 +293,22 @@ on how to create a hook for the `OFF_TOPIC` name:
|
||||
You can refer to `models/schema/tag.js` for the available schema to match when
|
||||
creating models to enable/disable specific features.
|
||||
|
||||
### Routes
|
||||
|
||||
#### Field: `router`
|
||||
|
||||
```js
|
||||
(router) => {
|
||||
router.get('/api/v1/people', (req, res) => {
|
||||
res.json({people: [{name: 'Bob'}]});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The Router hook allows you to create a function that accepts the base express
|
||||
router where you can mount any amount of middleware/routes to do any form of
|
||||
action needed by external applications.
|
||||
|
||||
### Authorization middleware
|
||||
|
||||
The following example creates the requisite callback route and passport
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
RECAPTCHA_PUBLIC
|
||||
RECAPTCHA_PUBLIC,
|
||||
WEBSOCKET_LIVE_URI,
|
||||
} = require('../../config');
|
||||
|
||||
// Get /email-confirmation expects a signed JWT in the hash
|
||||
@@ -20,7 +21,8 @@ router.get('/password-reset', (req, res) => {
|
||||
|
||||
router.get('*', (req, res) => {
|
||||
const data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
};
|
||||
|
||||
res.render('admin', {data});
|
||||
|
||||
+13
-14
@@ -2,25 +2,24 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
const SettingsService = require('../../services/settings');
|
||||
const {
|
||||
RECAPTCHA_PUBLIC
|
||||
RECAPTCHA_PUBLIC,
|
||||
WEBSOCKET_LIVE_URI,
|
||||
} = require('../../config');
|
||||
|
||||
router.use('/:embed', (req, res, next) => {
|
||||
router.use('/:embed', async (req, res, next) => {
|
||||
switch (req.params.embed) {
|
||||
case 'stream':
|
||||
return SettingsService.retrieve()
|
||||
.then(({customCssUrl}) => {
|
||||
const data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC
|
||||
};
|
||||
case 'stream': {
|
||||
const {customCssUrl} = await SettingsService.retrieve();
|
||||
const data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
};
|
||||
|
||||
return res.render('embed/stream', {customCssUrl, data});
|
||||
});
|
||||
default:
|
||||
|
||||
// will return a 404.
|
||||
return next();
|
||||
return res.render('embed/stream', {customCssUrl, data});
|
||||
}
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user