fix(HH-581): keep widget websocket on visitor auth (#152)
Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -11,15 +11,18 @@ class BaseActionCableConnector {
|
||||
app,
|
||||
pubsubToken,
|
||||
websocketHost = '',
|
||||
presenceInterval = PRESENCE_INTERVAL
|
||||
presenceInterval = PRESENCE_INTERVAL,
|
||||
useSessionAuth = true
|
||||
) {
|
||||
this.consumer = null;
|
||||
this.subscription = null;
|
||||
this.websocketHost = websocketHost;
|
||||
this.pubsubToken = pubsubToken;
|
||||
this.useSessionAuth = useSessionAuth;
|
||||
this.app = app;
|
||||
this.events = {};
|
||||
this.reconnectTimer = null;
|
||||
this.ticketFailureLogged = false;
|
||||
this.isAValidEvent = () => true;
|
||||
this.connect();
|
||||
this.triggerPresenceInterval = () => {
|
||||
@@ -34,14 +37,20 @@ class BaseActionCableConnector {
|
||||
async connect() {
|
||||
const wsOrigin = this.websocketHost || window.location.origin;
|
||||
let websocketURL = `${wsOrigin}/cable`;
|
||||
if (Cookies.get('cw_d_session_state')) {
|
||||
if (this.useSessionAuth && Cookies.get('cw_d_session_state')) {
|
||||
try {
|
||||
const response = await window.axios.post('/api/v1/auth/ws_ticket');
|
||||
const ticket = response.data?.data?.ticket;
|
||||
if (!ticket) throw new Error('missing websocket ticket');
|
||||
websocketURL += `?ticket=${encodeURIComponent(ticket)}`;
|
||||
this.usesWSTicket = true;
|
||||
this.ticketFailureLogged = false;
|
||||
} catch (error) {
|
||||
if (!this.ticketFailureLogged) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('WebSocket ticket exchange failed; retrying');
|
||||
this.ticketFailureLogged = true;
|
||||
}
|
||||
this.initReconnectTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,24 @@ describe('BaseActionCableConnector', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps widget token auth when a dashboard cookie shares its origin', () => {
|
||||
getCookie.mockReturnValue('dashboard-session');
|
||||
|
||||
const connector = new BaseActionCableConnector(
|
||||
app,
|
||||
'visitor token',
|
||||
'',
|
||||
20000,
|
||||
false
|
||||
);
|
||||
|
||||
expect(post).not.toHaveBeenCalled();
|
||||
expect(createConsumer).toHaveBeenCalledWith(
|
||||
`${window.location.origin}/cable?pubsub_token=visitor%20token`
|
||||
);
|
||||
connector.disconnect();
|
||||
});
|
||||
|
||||
it('continues consuming widget events after ActionCable reconnects', async () => {
|
||||
getCookie.mockReturnValue(undefined);
|
||||
const connector = new BaseActionCableConnector(app, 'visitor-token');
|
||||
@@ -138,9 +156,19 @@ describe('BaseActionCableConnector', () => {
|
||||
getCookie.mockReturnValue('1');
|
||||
post.mockRejectedValue({ response: { status: 401 } });
|
||||
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
|
||||
new BaseActionCableConnector(app, 'pubsub');
|
||||
await vi.waitFor(() => expect(post).toHaveBeenCalledOnce());
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await vi.waitFor(() => expect(post).toHaveBeenCalledTimes(2));
|
||||
|
||||
expect(createConsumer).not.toHaveBeenCalled();
|
||||
expect(warn).toHaveBeenCalledOnce();
|
||||
expect(warn).toHaveBeenCalledWith(
|
||||
'WebSocket ticket exchange failed; retrying'
|
||||
);
|
||||
warn.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ const WIDGET_PRESENCE_INTERVAL = 60000;
|
||||
|
||||
class ActionCableConnector extends BaseActionCableConnector {
|
||||
constructor(app, pubsubToken) {
|
||||
super(app, pubsubToken, '', WIDGET_PRESENCE_INTERVAL);
|
||||
super(app, pubsubToken, '', WIDGET_PRESENCE_INTERVAL, false);
|
||||
this.events = {
|
||||
'message.created': this.onMessageCreated,
|
||||
'message.updated': this.onMessageUpdated,
|
||||
|
||||
@@ -53,6 +53,10 @@ describe('Widget ActionCableConnector', () => {
|
||||
});
|
||||
};
|
||||
|
||||
it('uses visitor-token auth even when a dashboard session shares the origin', () => {
|
||||
expect(actionCable.useSessionAuth).toBe(false);
|
||||
});
|
||||
|
||||
it('emits message side effects only once when realtime replays a message', async () => {
|
||||
const message = {
|
||||
id: 42,
|
||||
|
||||
Reference in New Issue
Block a user