mirror of
https://github.com/wassname/talk.git
synced 2026-09-09 11:38:08 +08:00
[next] Support external config (#2088)
* fix: correctly determine expired token * feat: support external config * fix: lint * fix: npm audit fix
This commit is contained in:
@@ -109,7 +109,6 @@ it("submits form successfully", async () => {
|
||||
})
|
||||
)}.${btoa(
|
||||
JSON.stringify({
|
||||
exp: 1540503165,
|
||||
jti: "31b26591-4e9a-4388-a7ff-e1bdc5d97cce",
|
||||
})
|
||||
)}`;
|
||||
|
||||
@@ -3,11 +3,13 @@ import qs from "query-string";
|
||||
|
||||
import ensureNoEndSlash from "talk-common/utils/ensureNoEndSlash";
|
||||
import urls from "talk-framework/helpers/urls";
|
||||
import { ExternalConfig } from "talk-framework/lib/externalConfig";
|
||||
|
||||
import {
|
||||
Decorator,
|
||||
withAutoHeight,
|
||||
withClickEvent,
|
||||
withConfig,
|
||||
withEventEmitter,
|
||||
withIOSSafariWidthWorkaround,
|
||||
withPymStorage,
|
||||
@@ -28,6 +30,7 @@ export interface StreamEmbedConfig {
|
||||
eventEmitter: EventEmitter2;
|
||||
id: string;
|
||||
rootURL: string;
|
||||
authToken?: string;
|
||||
}
|
||||
|
||||
export class StreamEmbed {
|
||||
@@ -97,6 +100,11 @@ export class StreamEmbed {
|
||||
if (this.pymControl) {
|
||||
throw new Error("Stream Embed already rendered");
|
||||
}
|
||||
|
||||
const externalConfig: ExternalConfig = {
|
||||
authToken: this.config.authToken,
|
||||
};
|
||||
|
||||
const streamDecorators: ReadonlyArray<Decorator> = [
|
||||
withIOSSafariWidthWorkaround,
|
||||
withAutoHeight,
|
||||
@@ -105,6 +113,7 @@ export class StreamEmbed {
|
||||
withEventEmitter(this.config.eventEmitter),
|
||||
withPymStorage(localStorage, "localStorage"),
|
||||
withPymStorage(sessionStorage, "sessionStorage"),
|
||||
withConfig(externalConfig),
|
||||
];
|
||||
|
||||
const query = qs.stringify({
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface Config {
|
||||
id?: string;
|
||||
autoRender?: boolean;
|
||||
events?: (eventEmitter: EventEmitter2) => void;
|
||||
authToken?: string;
|
||||
}
|
||||
|
||||
function getLocationOrigin() {
|
||||
@@ -56,5 +57,6 @@ export function createStreamEmbed(config: Config): StreamEmbed {
|
||||
rootURL: config.rootURL || getLocationOrigin(),
|
||||
autoRender: config.autoRender,
|
||||
eventEmitter,
|
||||
authToken: config.authToken,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export { default as withClickEvent } from "./withClickEvent";
|
||||
export { default as withSetCommentID } from "./withSetCommentID";
|
||||
export { default as withEventEmitter } from "./withEventEmitter";
|
||||
export { default as withPymStorage } from "./withPymStorage";
|
||||
export { default as withConfig } from "./withConfig";
|
||||
export {
|
||||
default as withIOSSafariWidthWorkaround,
|
||||
} from "./withIOSSafariWidthWorkaround";
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import sinon from "sinon";
|
||||
|
||||
import withConfig from "./withConfig";
|
||||
|
||||
it("should emit events from pym to Config", () => {
|
||||
const config = { authToken: "token" };
|
||||
const fakePym = {
|
||||
onMessage: (type: string, callback: () => void) => {
|
||||
expect(type).toBe("getConfig");
|
||||
callback();
|
||||
},
|
||||
sendMessage: sinon
|
||||
.stub()
|
||||
.withArgs("config", JSON.stringify(config))
|
||||
.returns(null),
|
||||
};
|
||||
withConfig(config)(fakePym as any);
|
||||
expect(fakePym.sendMessage.calledOnce).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ExternalConfig } from "talk-framework/lib/externalConfig";
|
||||
|
||||
import { Decorator } from "./types";
|
||||
|
||||
const withConfig = (config: ExternalConfig): Decorator => pym => {
|
||||
pym.onMessage("getConfig", () => {
|
||||
pym.sendMessage("config", JSON.stringify(config));
|
||||
});
|
||||
};
|
||||
|
||||
export default withConfig;
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "es5"],
|
||||
"lib": ["dom", "es6"],
|
||||
"types": ["jest", "node"],
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Child as PymChild } from "pym.js";
|
||||
import { areWeInIframe } from "talk-framework/utils";
|
||||
|
||||
export interface ExternalConfig {
|
||||
authToken?: string;
|
||||
}
|
||||
|
||||
export function getExternalConfig(
|
||||
pym?: PymChild
|
||||
): Promise<ExternalConfig> | null {
|
||||
if (pym && areWeInIframe()) {
|
||||
return new Promise(resolve => {
|
||||
pym.sendMessage("getConfig", "");
|
||||
pym.onMessage("config", raw => {
|
||||
resolve(JSON.parse(raw) as ExternalConfig);
|
||||
});
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export function parseJWT(token: string, skewTolerance = 300): JWT {
|
||||
header,
|
||||
payload,
|
||||
get expired() {
|
||||
return Date.now() - skewTolerance < payload.exp;
|
||||
return Date.now() / 1000 - skewTolerance >= payload.exp;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,9 +41,12 @@ export function setAuthTokenInLocalState(
|
||||
|
||||
export async function initLocalBaseState(
|
||||
environment: Environment,
|
||||
{ localStorage }: TalkContext
|
||||
{ localStorage }: TalkContext,
|
||||
authToken?: string | null
|
||||
) {
|
||||
const authToken = await localStorage!.getItem("authToken");
|
||||
if (authToken === undefined) {
|
||||
authToken = await localStorage!.getItem("authToken");
|
||||
}
|
||||
|
||||
commitLocalUpdate(environment, s => {
|
||||
const root = s.getRoot();
|
||||
@@ -53,7 +56,7 @@ export async function initLocalBaseState(
|
||||
root.setLinkedRecord(localRecord, "local");
|
||||
|
||||
// Set auth token
|
||||
setAuthTokenInLocalState(authToken, s);
|
||||
setAuthTokenInLocalState(authToken || null, s);
|
||||
|
||||
// Create network Record
|
||||
const networkRecord = createAndRetain(
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Returns true if we are in an iframe.
|
||||
*/
|
||||
export default function areWeInIframe() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export { default as buildURL } from "./buildURL";
|
||||
export { default as parseURL } from "./parseURL";
|
||||
export { default as modifyQuery } from "./modifyQuery";
|
||||
export { default as areWeInIframe } from "./areWeInIframe";
|
||||
|
||||
@@ -2,6 +2,7 @@ import qs from "query-string";
|
||||
import { commitLocalUpdate, Environment } from "relay-runtime";
|
||||
|
||||
import { TalkContext } from "talk-framework/lib/bootstrap";
|
||||
import { getExternalConfig } from "talk-framework/lib/externalConfig";
|
||||
import { createAndRetain, initLocalBaseState } from "talk-framework/lib/relay";
|
||||
|
||||
import { AUTH_POPUP_ID, AUTH_POPUP_TYPE } from "./constants";
|
||||
@@ -13,7 +14,13 @@ export default async function initLocalState(
|
||||
environment: Environment,
|
||||
context: TalkContext
|
||||
) {
|
||||
await initLocalBaseState(environment, context);
|
||||
const config = await getExternalConfig(context.pym);
|
||||
await initLocalBaseState(
|
||||
environment,
|
||||
context,
|
||||
config ? config.authToken : undefined
|
||||
);
|
||||
|
||||
commitLocalUpdate(environment, s => {
|
||||
const root = s.getRoot();
|
||||
const localRecord = root.getLinkedRecord("local")!;
|
||||
|
||||
Reference in New Issue
Block a user