// *****************************************************************************
// Copyright (C) 2020 Ericsson 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
// *****************************************************************************

import { WsRequestValidatorContribution } from '@theia/core/lib/node/ws-request-validators';
import * as http from 'http';
import { injectable, postConstruct } from '@theia/core/shared/inversify';
import { MiniBrowserEndpoint } from '../common/mini-browser-endpoint';

/**
 * Prevents explicit WebSocket connections from the mini-browser virtual host.
 */
@injectable()
export class MiniBrowserWsRequestValidator implements WsRequestValidatorContribution {

    protected miniBrowserHostRe: RegExp;

    protected serveSameOrigin: boolean = false;

    @postConstruct()
    protected init(): void {
        const pattern = process.env[MiniBrowserEndpoint.HOST_PATTERN_ENV] || MiniBrowserEndpoint.HOST_PATTERN_DEFAULT;
        if (pattern === '{{hostname}}') {
            this.serveSameOrigin = true;
        }
        const vhostRe = pattern
            .replace(/\./g, '\\.')
            .replace('{{uuid}}', '.+')
            .replace('{{hostname}}', '.+');
        this.miniBrowserHostRe = new RegExp(vhostRe, 'i');
    }

    async allowWsUpgrade(request: http.IncomingMessage): Promise<boolean> {
        if (request.headers.origin && !this.serveSameOrigin) {
            let host: string | undefined;
            try {
                host = new URL(request.headers.origin).host;
            } catch {
                host = undefined;
            }
            if (host && this.miniBrowserHostRe.test(host)) {
                // If the origin comes from the WebViews, refuse:
                return false;
            }
        }
        return true;
    }
}
