@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
128 lines • 6.62 kB
JavaScript
;
// *****************************************************************************
// Copyright (C) 2026 STMicroelectronics and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const browser_connection_token_1 = require("./browser-connection-token");
describe('BrowserConnectionToken', () => {
it('should generate unique tokens', () => {
const token1 = (0, browser_connection_token_1.createBrowserConnectionToken)();
const token2 = (0, browser_connection_token_1.createBrowserConnectionToken)();
(0, chai_1.expect)(token1.value).to.not.equal(token2.value);
});
it('should generate tokens of sufficient length', () => {
const token = (0, browser_connection_token_1.createBrowserConnectionToken)();
(0, chai_1.expect)(token.value.length).to.be.greaterThan(16);
});
});
describe('BrowserConnectionTokenBackendContribution', () => {
const token = (0, browser_connection_token_1.createBrowserConnectionToken)();
function createContribution() {
const contribution = new browser_connection_token_1.BrowserConnectionTokenBackendContribution();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
contribution['browserConnectionToken'] = token;
return contribution;
}
function createRequest(cookieValue) {
const request = {
headers: {}
};
if (cookieValue !== undefined) {
request.headers.cookie = `${browser_connection_token_1.BROWSER_TOKEN_COOKIE_NAME}=${cookieValue}`;
}
return request;
}
describe('allowWsUpgrade (WebSocket validation)', () => {
it('should allow WebSocket with valid token cookie', () => {
const contribution = createContribution();
(0, chai_1.expect)(contribution.allowWsUpgrade(createRequest(token.value))).to.be.true;
});
it('should reject WebSocket with no cookie', () => {
const contribution = createContribution();
(0, chai_1.expect)(contribution.allowWsUpgrade(createRequest())).to.be.false;
});
it('should reject WebSocket with invalid token', () => {
const contribution = createContribution();
(0, chai_1.expect)(contribution.allowWsUpgrade(createRequest('wrong-token'))).to.be.false;
});
it('should reject WebSocket with stale token from previous server', () => {
const contribution = createContribution();
const staleToken = (0, browser_connection_token_1.createBrowserConnectionToken)().value;
(0, chai_1.expect)(contribution.allowWsUpgrade(createRequest(staleToken))).to.be.false;
});
it('should reject WebSocket with empty token', () => {
const contribution = createContribution();
(0, chai_1.expect)(contribution.allowWsUpgrade(createRequest(''))).to.be.false;
});
it('should handle multiple cookies correctly', () => {
const contribution = createContribution();
const request = {
headers: {
cookie: `other-cookie=foo; ${browser_connection_token_1.BROWSER_TOKEN_COOKIE_NAME}=${token.value}; another=bar`
}
};
(0, chai_1.expect)(contribution.allowWsUpgrade(request)).to.be.true;
});
});
describe('expressMiddleware (HTTP cookie flow)', () => {
function callMiddleware(cookieValue) {
const contribution = createContribution();
const result = { cookieCalls: [], nextCalled: false };
const req = {
headers: {},
socket: { remoteAddress: '127.0.0.1' }
};
if (cookieValue !== undefined) {
req.headers.cookie = `${browser_connection_token_1.BROWSER_TOKEN_COOKIE_NAME}=${cookieValue}`;
}
const res = {
cookie: (name, value, options) => {
result.cookieCalls.push({ name, value, options });
}
};
const next = () => { result.nextCalled = true; };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
contribution.expressMiddleware(req, res, next);
return result;
}
it('should set cookie and allow request when no cookie present', () => {
const result = callMiddleware();
(0, chai_1.expect)(result.nextCalled).to.be.true;
(0, chai_1.expect)(result.cookieCalls).to.have.length(1);
(0, chai_1.expect)(result.cookieCalls[0].name).to.equal(browser_connection_token_1.BROWSER_TOKEN_COOKIE_NAME);
(0, chai_1.expect)(result.cookieCalls[0].value).to.equal(token.value);
});
it('should set cookie with HttpOnly, SameSite=Strict, and path=/', () => {
const result = callMiddleware();
const opts = result.cookieCalls[0].options;
(0, chai_1.expect)(opts.httpOnly).to.be.true;
(0, chai_1.expect)(opts.sameSite).to.equal('strict');
(0, chai_1.expect)(opts.path).to.equal('/');
});
it('should allow request with valid cookie without re-setting it', () => {
const result = callMiddleware(token.value);
(0, chai_1.expect)(result.nextCalled).to.be.true;
(0, chai_1.expect)(result.cookieCalls).to.have.length(0);
});
it('should refresh stale cookie and allow request', () => {
const result = callMiddleware('stale-token-from-old-server');
(0, chai_1.expect)(result.nextCalled).to.be.true;
(0, chai_1.expect)(result.cookieCalls).to.have.length(1);
(0, chai_1.expect)(result.cookieCalls[0].value).to.equal(token.value);
});
});
});
//# sourceMappingURL=browser-connection-token.spec.js.map