mirror of
https://github.com/hexastack/hexabot
synced 2025-01-22 10:35:37 +00:00
refactor: remove widget token
This commit is contained in:
parent
81a507d091
commit
9df4fbbdad
@ -1,5 +1,4 @@
|
||||
{
|
||||
"verification_token": "Verification Token",
|
||||
"allowed_domains": "Allowed Domains",
|
||||
"start_button": "Enable `Get Started`",
|
||||
"input_disabled": "Disable Input",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"verification_token": "Jeton de vérification",
|
||||
"allowed_domains": "Domaines autorisés",
|
||||
"start_button": "Activer `Démarrer`",
|
||||
"input_disabled": "Désactiver la saisie",
|
||||
|
@ -17,12 +17,6 @@ export const CONSOLE_CHANNEL_NAME = 'console-channel';
|
||||
export const CONSOLE_CHANNEL_NAMESPACE = 'console_channel';
|
||||
|
||||
export default [
|
||||
{
|
||||
group: CONSOLE_CHANNEL_NAMESPACE,
|
||||
label: Web.SettingLabel.verification_token,
|
||||
value: 'test',
|
||||
type: SettingType.text,
|
||||
},
|
||||
{
|
||||
group: CONSOLE_CHANNEL_NAMESPACE,
|
||||
label: Web.SettingLabel.allowed_domains,
|
||||
|
@ -77,7 +77,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
protected readonly attachmentService: AttachmentService,
|
||||
protected readonly messageService: MessageService,
|
||||
protected readonly menuService: MenuService,
|
||||
private readonly websocketGateway: WebsocketGateway,
|
||||
protected readonly websocketGateway: WebsocketGateway,
|
||||
) {
|
||||
super(name, settingService, channelService, logger);
|
||||
}
|
||||
@ -98,42 +98,32 @@ export default abstract class BaseWebChannelHandler<
|
||||
*/
|
||||
@OnEvent('hook:websocket:connection', { async: true })
|
||||
async onWebSocketConnection(client: Socket) {
|
||||
const settings = await this.getSettings();
|
||||
const handshake = client.handshake;
|
||||
const { channel } = handshake.query;
|
||||
if (channel !== this.getName()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { verification_token } = client.handshake.query;
|
||||
await this.verifyToken(verification_token.toString());
|
||||
try {
|
||||
this.logger.debug(
|
||||
'Web Channel Handler : WS connected .. sending settings',
|
||||
);
|
||||
try {
|
||||
const menu = await this.menuService.getTree();
|
||||
return client.emit('settings', { menu, ...settings });
|
||||
} catch (err) {
|
||||
this.logger.warn(
|
||||
'Web Channel Handler : Unable to retrieve menu ',
|
||||
err,
|
||||
);
|
||||
return client.emit('settings', settings);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.warn(
|
||||
'Web Channel Handler : Unable to verify token, disconnecting ...',
|
||||
err,
|
||||
);
|
||||
client.disconnect();
|
||||
const settings = await this.getSettings();
|
||||
const handshake = client.handshake;
|
||||
const { channel } = handshake.query;
|
||||
|
||||
if (channel !== this.getName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug(
|
||||
'Web Channel Handler : WS connected .. sending settings',
|
||||
);
|
||||
|
||||
try {
|
||||
const menu = await this.menuService.getTree();
|
||||
return client.emit('settings', { menu, ...settings });
|
||||
} catch (err) {
|
||||
this.logger.warn('Web Channel Handler : Unable to retrieve menu ', err);
|
||||
return client.emit('settings', settings);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
'Web Channel Handler : Unable to initiate websocket connection',
|
||||
err,
|
||||
);
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +208,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
*
|
||||
* @returns Formatted message
|
||||
*/
|
||||
private formatHistoryMessages(messages: AnyMessage[]): Web.Message[] {
|
||||
protected formatMessages(messages: AnyMessage[]): Web.Message[] {
|
||||
return messages.map((anyMessage: AnyMessage) => {
|
||||
if ('sender' in anyMessage && anyMessage.sender) {
|
||||
return {
|
||||
@ -262,7 +252,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
until,
|
||||
n,
|
||||
);
|
||||
return this.formatHistoryMessages(messages.reverse());
|
||||
return this.formatMessages(messages.reverse());
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@ -287,35 +277,11 @@ export default abstract class BaseWebChannelHandler<
|
||||
since,
|
||||
n,
|
||||
);
|
||||
return this.formatHistoryMessages(messages);
|
||||
return this.formatMessages(messages);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the received token.
|
||||
*
|
||||
* @param verificationToken - Verification Token
|
||||
*/
|
||||
private async verifyToken(verificationToken: string) {
|
||||
const settings =
|
||||
(await this.getSettings()) as unknown as Settings[typeof WEB_CHANNEL_NAMESPACE];
|
||||
const verifyToken = settings.verification_token;
|
||||
|
||||
if (!verifyToken) {
|
||||
throw new Error('You need to specify a verifyToken in your config.');
|
||||
}
|
||||
if (!verificationToken) {
|
||||
throw new Error('Did not recieve any verification token.');
|
||||
}
|
||||
if (verificationToken !== verifyToken) {
|
||||
throw new Error('Make sure the validation tokens match.');
|
||||
}
|
||||
this.logger.log(
|
||||
'Web Channel Handler : Token has been verified successfully!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the origin against whitelisted domains.
|
||||
*
|
||||
@ -405,20 +371,12 @@ export default abstract class BaseWebChannelHandler<
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
private async checkRequest(
|
||||
protected async checkRequest(
|
||||
req: Request | SocketRequest,
|
||||
res: Response | SocketResponse,
|
||||
) {
|
||||
try {
|
||||
await this.validateCors(req, res);
|
||||
try {
|
||||
const { verification_token } =
|
||||
'verification_token' in req.query ? req.query : req.body;
|
||||
await this.verifyToken(verification_token);
|
||||
} catch (err) {
|
||||
this.logger.warn('Web Channel Handler : Unable to verify token ', err);
|
||||
throw new Error('Unauthorized, invalid token!');
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.warn(
|
||||
'Web Channel Handler : Attempt to access from an unauthorized origin',
|
||||
@ -741,7 +699,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
*
|
||||
* @returns IP Address
|
||||
*/
|
||||
private getIpAddress(req: Request | SocketRequest): string {
|
||||
protected getIpAddress(req: Request | SocketRequest): string {
|
||||
if ('isSocket' in req && req.isSocket) {
|
||||
return req.socket.handshake.address;
|
||||
} else if (Array.isArray(req.ips) && req.ips.length > 0) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"verification_token": "Verification Token",
|
||||
"allowed_domains": "Allowed Domains",
|
||||
"start_button": "Enable `Get Started`",
|
||||
"input_disabled": "Disable Input",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"verification_token": "Jeton de vérification",
|
||||
"allowed_domains": "Domaines autorisés",
|
||||
"start_button": "Activer `Démarrer`",
|
||||
"input_disabled": "Désactiver la saisie",
|
||||
|
@ -16,12 +16,6 @@ export const WEB_CHANNEL_NAME = 'web-channel' as const;
|
||||
export const WEB_CHANNEL_NAMESPACE = 'web_channel';
|
||||
|
||||
export default [
|
||||
{
|
||||
group: WEB_CHANNEL_NAMESPACE,
|
||||
label: Web.SettingLabel.verification_token,
|
||||
value: 'token123',
|
||||
type: SettingType.secret,
|
||||
},
|
||||
{
|
||||
group: WEB_CHANNEL_NAMESPACE,
|
||||
label: Web.SettingLabel.allowed_domains,
|
||||
|
@ -13,8 +13,6 @@ import { StdQuickReply } from '@/chat/schemas/types/quick-reply';
|
||||
|
||||
export namespace Web {
|
||||
export enum SettingLabel {
|
||||
secret = 'secret',
|
||||
verification_token = 'verification_token',
|
||||
allowed_domains = 'allowed_domains',
|
||||
start_button = 'start_button',
|
||||
input_disabled = 'input_disabled',
|
||||
|
@ -224,7 +224,7 @@ export class WebsocketGateway
|
||||
'Unable to load session, creating a new one ...',
|
||||
err,
|
||||
);
|
||||
if (searchParams.get('channel') === 'web-channel') {
|
||||
if (searchParams.get('channel') !== 'console-channel') {
|
||||
return this.createAndStoreSession(client, next);
|
||||
} else {
|
||||
return next(new Error('Unauthorized: Unknown session ID'));
|
||||
|
@ -58,4 +58,3 @@ NEXT_PUBLIC_SSO_ENABLED=false
|
||||
APP_WIDGET_PORT=5173
|
||||
REACT_APP_WIDGET_API_URL=http://${APP_DOMAIN}:${API_PORT}
|
||||
REACT_APP_WIDGET_CHANNEL=web-channel
|
||||
REACT_APP_WIDGET_TOKEN=token123
|
||||
|
@ -34,7 +34,6 @@ export const ChatWidget = () => {
|
||||
config={{
|
||||
apiUrl,
|
||||
channel: "console-channel",
|
||||
token: "test",
|
||||
language: i18n.language,
|
||||
}}
|
||||
CustomHeader={ChatWidgetHeader}
|
||||
|
@ -7,11 +7,9 @@ COPY package*.json ./
|
||||
# Set the environment variables
|
||||
ARG REACT_APP_WIDGET_API_URL
|
||||
ARG REACT_APP_WIDGET_CHANNEL
|
||||
ARG REACT_APP_WIDGET_TOKEN
|
||||
|
||||
ENV REACT_APP_WIDGET_API_URL=${REACT_APP_WIDGET_API_URL}
|
||||
ENV REACT_APP_WIDGET_CHANNEL=${REACT_APP_WIDGET_CHANNEL}
|
||||
ENV REACT_APP_WIDGET_TOKEN=${REACT_APP_WIDGET_TOKEN}
|
||||
|
||||
# Installer stage: Installs dependencies
|
||||
FROM base AS installer
|
||||
|
@ -20,7 +20,6 @@ import { useColors } from '../providers/ColorProvider';
|
||||
import { useConfig } from '../providers/ConfigProvider';
|
||||
import { useSettings } from '../providers/SettingsProvider';
|
||||
import { useSocket } from '../providers/SocketProvider';
|
||||
import './UserSubscription.scss';
|
||||
import { useWidget } from '../providers/WidgetProvider';
|
||||
import {
|
||||
Direction,
|
||||
@ -28,6 +27,7 @@ import {
|
||||
TMessage,
|
||||
TOutgoingMessageType,
|
||||
} from '../types/message.types';
|
||||
import './UserSubscription.scss';
|
||||
|
||||
const UserSubscription: React.FC = () => {
|
||||
const config = useConfig();
|
||||
@ -55,7 +55,7 @@ const UserSubscription: React.FC = () => {
|
||||
messages: TMessage[];
|
||||
profile: ISubscriber;
|
||||
}>(
|
||||
`/webhook/${config.channel}/?verification_token=${config.token}&first_name=${firstName}&last_name=${lastName}`,
|
||||
`/webhook/${config.channel}/?first_name=${firstName}&last_name=${lastName}`,
|
||||
);
|
||||
const { messages, profile } = body;
|
||||
|
||||
|
@ -9,6 +9,5 @@
|
||||
export const DEFAULT_CONFIG = {
|
||||
apiUrl: process.env.REACT_APP_WIDGET_API_URL || 'http://localhost:4000',
|
||||
channel: process.env.REACT_APP_WIDGET_CHANNEL || 'console-channel',
|
||||
token: process.env.REACT_APP_WIDGET_TOKEN || 'test',
|
||||
language: 'en',
|
||||
};
|
||||
|
@ -19,7 +19,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
{...{
|
||||
apiUrl: process.env.REACT_APP_WIDGET_API_URL || 'http://localhost:4000',
|
||||
channel: process.env.REACT_APP_WIDGET_CHANNEL || 'web-channel',
|
||||
token: process.env.REACT_APP_WIDGET_TOKEN || 'token123',
|
||||
language: 'en',
|
||||
}}
|
||||
/>
|
||||
|
@ -289,7 +289,7 @@ const ChatProvider: React.FC<{
|
||||
);
|
||||
setMessage('');
|
||||
const sentMessage = await socketCtx.socket.post<TMessage>(
|
||||
`/webhook/${config.channel}/?verification_token=${config.token}`,
|
||||
`/webhook/${config.channel}/`,
|
||||
{
|
||||
data: {
|
||||
...data,
|
||||
@ -308,7 +308,7 @@ const ChatProvider: React.FC<{
|
||||
messages: TMessage[];
|
||||
profile: ISubscriber;
|
||||
}>(
|
||||
`/webhook/${config.channel}/?verification_token=${config.token}&first_name=${firstName}&last_name=${lastName}`,
|
||||
`/webhook/${config.channel}/?first_name=${firstName}&last_name=${lastName}`,
|
||||
);
|
||||
|
||||
localStorage.setItem('profile', JSON.stringify(body.profile));
|
||||
|
@ -13,7 +13,6 @@ import { DEFAULT_CONFIG } from '../constants/defaultConfig';
|
||||
// Define the type for your config, including all possible properties
|
||||
export type Config = {
|
||||
apiUrl: string;
|
||||
token: string;
|
||||
channel: string;
|
||||
language: string;
|
||||
};
|
||||
@ -23,7 +22,6 @@ const ConfigContext = createContext<Config>(DEFAULT_CONFIG);
|
||||
|
||||
export const ConfigProvider: React.FC<{
|
||||
apiUrl?: string;
|
||||
token?: string;
|
||||
channel?: string;
|
||||
language?: string;
|
||||
children: ReactNode;
|
||||
|
@ -23,7 +23,6 @@ import { useSubscribe } from './SocketProvider';
|
||||
type ChannelSettings = {
|
||||
menu: IMenuNode[];
|
||||
secret: string;
|
||||
verification_token: string;
|
||||
allowed_domains: string;
|
||||
start_button: boolean;
|
||||
input_disabled: boolean;
|
||||
|
@ -6,7 +6,7 @@
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
import { io, Socket, ManagerOptions, SocketOptions } from 'socket.io-client';
|
||||
import { io, ManagerOptions, Socket, SocketOptions } from 'socket.io-client';
|
||||
|
||||
import { Config } from '../providers/ConfigProvider';
|
||||
import {
|
||||
@ -195,14 +195,16 @@ let socketIoClient: SocketIoClient;
|
||||
* @param handlers Event handlers
|
||||
* @returns Socket io client instance
|
||||
*/
|
||||
export const getSocketIoClient = (config: Config, handlers: SocketIoEventHandlers) => {
|
||||
export const getSocketIoClient = (
|
||||
config: Config,
|
||||
handlers: SocketIoEventHandlers,
|
||||
) => {
|
||||
if (!socketIoClient) {
|
||||
socketIoClient = new SocketIoClient(
|
||||
config.apiUrl,
|
||||
{
|
||||
query: {
|
||||
channel: config.channel,
|
||||
verification_token: config.token,
|
||||
},
|
||||
},
|
||||
handlers,
|
||||
|
Loading…
Reference in New Issue
Block a user