1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add TLS support

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-12-09 15:52:21 -05:00
parent 7708e662e1
commit 7df0f098f1
41 changed files with 355 additions and 149 deletions

View File

@ -26,7 +26,7 @@ async function getMainWindow(app: ElectronApplication, timeout = 50_000): Promis
const onWindow = (page: Page) => {
console.log(`Page opened: ${page.url()}`);
if (page.url().startsWith("http://localhost")) {
if (page.url().startsWith("https://localhost")) {
cleanup();
console.log(stdoutBuf);
resolve(page);

View File

@ -57,7 +57,7 @@
"bundledKubectlVersion": "1.23.3",
"bundledHelmVersion": "3.7.2",
"sentryDsn": "",
"contentSecurityPolicy": "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
"contentSecurityPolicy": "script-src 'unsafe-eval' 'self'; img-src * data:",
"welcomeRoute": "/welcome"
},
"engines": {

View File

@ -0,0 +1,9 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { SelfSignedCert } from "selfsigned";
import { getRequestChannel } from "../utils/channel/request-channel-listener-injection-token";
export const lensProxyCertificateChannel = getRequestChannel<void, SelfSignedCert>("request-lens-proxy-certificate");

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { SelfSignedCert } from "selfsigned";
export const lensProxyCertificateInjectionToken = getInjectionToken<SelfSignedCert>({
id: "lens-proxy-certificate-token",
});

View File

@ -3,20 +3,27 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { Agent } from "https";
import type { RequestInit, Response } from "node-fetch";
import { lensAuthenticationHeaderValueInjectionToken } from "../auth/header-value";
import { lensProxyCertificateInjectionToken } from "../certificate/token";
import { lensAuthenticationHeader } from "../vars/auth-header";
import fetchModuleInjectable from "./fetch-module.injectable";
import type { Fetch } from "./fetch.injectable";
import fetchInjectable from "./fetch.injectable";
export type AuthenticatedRequestInit = Omit<RequestInit, "agent">;
export type AuthenticatedFetch = (url: string, options?: AuthenticatedRequestInit) => Promise<Response>;
/**
* This injectable should not be used to request data from external sources as it would leak the
* authentication header value
*/
const lensAuthenticatedFetchInjectable = getInjectable({
id: "lens-authenticated-fetch",
instantiate: (di): Fetch => {
instantiate: (di): AuthenticatedFetch => {
const authHeaderValue = di.inject(lensAuthenticationHeaderValueInjectionToken);
const lensProxyCertificate = di.inject(lensProxyCertificateInjectionToken);
const fetch = di.inject(fetchInjectable);
const { Headers } = di.inject(fetchModuleInjectable);
@ -26,12 +33,16 @@ const lensAuthenticatedFetchInjectable = getInjectable({
...rest
} = init ?? {};
const headers = new Headers(headersInit);
const agent = new Agent({
ca: lensProxyCertificate.cert,
});
headers.set(lensAuthenticationHeader, authHeaderValue);
return fetch(url, {
headers,
...rest,
agent,
});
};
},

View File

@ -49,7 +49,7 @@ describe("KubeApi", () => {
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
request = createKubeJsonApi({
serverAddress: `http://127.0.0.1:9999`,
serverAddress: `https://127.0.0.1:9999`,
apiBase: "/api-kube",
});
registerApiSpy = jest.spyOn(di.inject(apiManagerInjectable), "registerApi");
@ -82,7 +82,7 @@ describe("KubeApi", () => {
it("requests version list from the api group from the initial apiBase", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io",
{
headers: {
"content-type": "application/json",
@ -95,8 +95,8 @@ describe("KubeApi", () => {
describe("when the version list from the api group resolves", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io", JSON.stringify({
apiVersion: "v1",
kind: "APIGroup",
name: "networking.k8s.io",
@ -120,7 +120,7 @@ describe("KubeApi", () => {
it("requests resources from the versioned api group from the initial apiBase", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1",
{
headers: {
"content-type": "application/json",
@ -133,8 +133,8 @@ describe("KubeApi", () => {
describe("when resource request fufills with a resource", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1", JSON.stringify({
resources: [{
name: "ingresses",
}],
@ -144,7 +144,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo",
{
headers: {
"content-type": "application/json",
@ -171,8 +171,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo", JSON.stringify({})),
);
result = await getCall;
});
@ -196,7 +196,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -211,8 +211,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});
@ -229,8 +229,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo", JSON.stringify({
apiVersion: "v1",
kind: "Ingress",
metadata: {
@ -263,7 +263,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -278,8 +278,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});
@ -295,8 +295,8 @@ describe("KubeApi", () => {
describe("when resource request fufills with no resource", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1", JSON.stringify({
resources: [],
})),
);
@ -304,7 +304,7 @@ describe("KubeApi", () => {
it("requests resources from the second versioned api group from the initial apiBase", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1",
{
headers: {
"content-type": "application/json",
@ -319,8 +319,8 @@ describe("KubeApi", () => {
describe("when resource request fufills with a resource", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1", JSON.stringify({
resources: [{
name: "ingresses",
}],
@ -330,7 +330,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo",
{
headers: {
"content-type": "application/json",
@ -357,8 +357,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({})),
);
result = await getCall;
});
@ -382,7 +382,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -397,8 +397,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});
@ -415,8 +415,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({
apiVersion: "v1",
kind: "Ingress",
metadata: {
@ -449,7 +449,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -464,8 +464,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});
@ -483,8 +483,8 @@ describe("KubeApi", () => {
describe("when the version list from the api group resolves with no versions", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/networking.k8s.io"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/networking.k8s.io", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/networking.k8s.io"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/networking.k8s.io", JSON.stringify({
"metadata": {},
"status": "Failure",
"message": "the server could not find the requested resource",
@ -504,7 +504,7 @@ describe("KubeApi", () => {
it("requests the resources from the base api url from the fallback api", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/extensions",
"https://127.0.0.1:9999/api-kube/apis/extensions",
{
headers: {
"content-type": "application/json",
@ -517,8 +517,8 @@ describe("KubeApi", () => {
describe("when resource request fufills with a resource", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/extensions"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions", JSON.stringify({
apiVersion: "v1",
kind: "APIGroup",
name: "extensions",
@ -538,7 +538,7 @@ describe("KubeApi", () => {
it("requests resource versions from the versioned api group from the fallback apiBase", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1",
"https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1",
{
headers: {
"content-type": "application/json",
@ -551,8 +551,8 @@ describe("KubeApi", () => {
describe("when the preferred version request resolves to v1beta1", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions", JSON.stringify({
resources: [{
name: "ingresses",
}],
@ -562,7 +562,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo",
"https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo",
{
headers: {
"content-type": "application/json",
@ -589,8 +589,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({})),
);
result = await getCall;
});
@ -614,7 +614,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -629,8 +629,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});
@ -647,8 +647,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo", JSON.stringify({
apiVersion: "v1beta1",
kind: "Ingress",
metadata: {
@ -681,7 +681,7 @@ describe("KubeApi", () => {
it("makes the request to get the resource", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1",
"https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1",
{
headers: {
"content-type": "application/json",
@ -696,8 +696,8 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
["https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/extensions/v1beta1/namespaces/default/ingresses/foo1", JSON.stringify({})),
);
result = await getCall;
});

View File

@ -157,7 +157,7 @@ describe("KubeApi", () => {
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
request = createKubeJsonApi({
serverAddress: `http://127.0.0.1:9999`,
serverAddress: `https://127.0.0.1:9999`,
apiBase: "/api-kube",
});
@ -189,7 +189,7 @@ describe("KubeApi", () => {
it("requests a patch using strategic merge", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
"https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
{
headers: {
"content-type": "application/strategic-merge-patch+json",
@ -203,8 +203,8 @@ describe("KubeApi", () => {
describe("when the patch request resolves with data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
apiVersion: "v1",
kind: "Deployment",
metadata: {
@ -240,7 +240,7 @@ describe("KubeApi", () => {
it("requests a patch using json merge", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
"https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
{
headers: {
"content-type": "application/json-patch+json",
@ -256,8 +256,8 @@ describe("KubeApi", () => {
describe("when the patch request resolves with data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
apiVersion: "v1",
kind: "Deployment",
metadata: {
@ -295,7 +295,7 @@ describe("KubeApi", () => {
it("requests a patch using json merge", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
"https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test",
{
headers: {
"content-type": "application/merge-patch+json",
@ -309,8 +309,8 @@ describe("KubeApi", () => {
describe("when the patch request resolves with data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
["https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/apis/apps/v1/namespaces/default/deployments/test", JSON.stringify({
apiVersion: "v1",
kind: "Deployment",
metadata: {
@ -354,7 +354,7 @@ describe("KubeApi", () => {
it("requests deleting pod in default namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background",
{
headers: {
"content-type": "application/json",
@ -367,8 +367,8 @@ describe("KubeApi", () => {
describe("when request resolves", () => {
beforeEach(async () => {
fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
);
});
@ -390,7 +390,7 @@ describe("KubeApi", () => {
it("requests deleting pod in default namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background",
{
headers: {
"content-type": "application/json",
@ -403,8 +403,8 @@ describe("KubeApi", () => {
describe("when request resolves", () => {
beforeEach(async () => {
fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
);
});
@ -426,7 +426,7 @@ describe("KubeApi", () => {
it("requests deleting pod in given namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background",
{
headers: {
"content-type": "application/json",
@ -439,8 +439,8 @@ describe("KubeApi", () => {
describe("when request resolves", () => {
beforeEach(async () => {
fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background", "{}"),
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background", "{}"),
);
});
@ -472,7 +472,7 @@ describe("KubeApi", () => {
it("requests deleting Namespace without namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background",
{
headers: {
"content-type": "application/json",
@ -485,8 +485,8 @@ describe("KubeApi", () => {
describe("when request resolves", () => {
beforeEach(async () => {
fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
);
});
@ -508,7 +508,7 @@ describe("KubeApi", () => {
it("requests deleting Namespace without namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background",
{
headers: {
"content-type": "application/json",
@ -521,8 +521,8 @@ describe("KubeApi", () => {
describe("when request resolves", () => {
beforeEach(async () => {
fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
);
});
@ -571,7 +571,7 @@ describe("KubeApi", () => {
it("requests the watch", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600",
{
headers: {
"content-type": "application/json",
@ -585,7 +585,7 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
([url, init]) => {
const isMatch = url === "http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600";
const isMatch = url === "https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600";
if (isMatch) {
init?.signal?.addEventListener("abort", () => {
@ -595,7 +595,7 @@ describe("KubeApi", () => {
return isMatch;
},
createMockResponseFromStream("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600", stream),
createMockResponseFromStream("https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600", stream),
);
});
@ -667,7 +667,7 @@ describe("KubeApi", () => {
it("requests the watch", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600",
{
headers: {
"content-type": "application/json",
@ -681,7 +681,7 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
([url, init]) => {
const isMatch = url === "http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600";
const isMatch = url === "https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600";
if (isMatch) {
init?.signal?.addEventListener("abort", () => {
@ -691,7 +691,7 @@ describe("KubeApi", () => {
return isMatch;
},
createMockResponseFromStream("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600", stream),
createMockResponseFromStream("https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=600", stream),
);
});
@ -762,7 +762,7 @@ describe("KubeApi", () => {
it("requests the watch", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60",
{
headers: {
"content-type": "application/json",
@ -776,7 +776,7 @@ describe("KubeApi", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
([url, init]) => {
const isMatch = url === "http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60";
const isMatch = url === "https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60";
if (isMatch) {
init?.signal?.addEventListener("abort", () => {
@ -786,7 +786,7 @@ describe("KubeApi", () => {
return isMatch;
},
createMockResponseFromStream("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60", stream),
createMockResponseFromStream("https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60", stream),
);
});
@ -844,7 +844,7 @@ describe("KubeApi", () => {
it("requests a new watch", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods?watch=1&resourceVersion=&timeoutSeconds=60",
{
headers: {
"content-type": "application/json",
@ -914,7 +914,7 @@ describe("KubeApi", () => {
it("should request to create a pod with full descriptor", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods",
{
headers: {
"content-type": "application/json",
@ -949,8 +949,8 @@ describe("KubeApi", () => {
describe("when request resolves with data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods", JSON.stringify({
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods", JSON.stringify({
kind: "Pod",
apiVersion: "v1",
metadata: {
@ -1026,7 +1026,7 @@ describe("KubeApi", () => {
it("should request that the pod is updated", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar",
{
headers: {
"content-type": "application/json",
@ -1061,8 +1061,8 @@ describe("KubeApi", () => {
describe("when the request resolves with data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar", JSON.stringify({
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foobar", JSON.stringify({
kind: "Pod",
apiVersion: "v1",
metadata: {
@ -1116,7 +1116,7 @@ describe("KubeApi", () => {
it("should request that the pods from all namespaces", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/pods",
"https://127.0.0.1:9999/api-kube/api/v1/pods",
{
headers: {
"content-type": "application/json",
@ -1129,8 +1129,8 @@ describe("KubeApi", () => {
describe("when the request resolves with empty data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/pods"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/pods", JSON.stringify({
["https://127.0.0.1:9999/api-kube/api/v1/pods"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/pods", JSON.stringify({
kind: "PodList",
apiVersion: "v1",
metadata: {},
@ -1158,7 +1158,7 @@ describe("KubeApi", () => {
it("should request that the pods from all namespaces", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/pods",
"https://127.0.0.1:9999/api-kube/api/v1/pods",
{
headers: {
"content-type": "application/json",
@ -1171,8 +1171,8 @@ describe("KubeApi", () => {
describe("when the request resolves with empty data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/pods"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/pods", JSON.stringify({
["https://127.0.0.1:9999/api-kube/api/v1/pods"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/pods", JSON.stringify({
kind: "PodList",
apiVersion: "v1",
metadata: {},
@ -1200,7 +1200,7 @@ describe("KubeApi", () => {
it("should request that the pods from just the default namespace", () => {
expect(fetchMock.mock.lastCall).toMatchObject([
"http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods",
"https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods",
{
headers: {
"content-type": "application/json",
@ -1213,8 +1213,8 @@ describe("KubeApi", () => {
describe("when the request resolves with empty data", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific(
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods"],
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods", JSON.stringify({
["https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods"],
createMockResponseFromString("https://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods", JSON.stringify({
kind: "PodList",
apiVersion: "v1",
metadata: {},

View File

@ -23,7 +23,7 @@ export interface IKubeApiParsed extends IKubeApiLinkRef {
}
export function parseKubeApi(path: string): IKubeApiParsed {
const apiPath = new URL(path, "http://localhost").pathname;
const apiPath = new URL(path, "https://localhost").pathname;
const [, prefix, ...parts] = apiPath.split("/");
const apiPrefix = `/${prefix}`;
const [left, right, namespaced] = splitArray(parts, "namespaces");

View File

@ -51,7 +51,7 @@ export interface BaseKubeJsonApiObjectMetadata<Namespaced extends KubeObjectScop
* external tools to store and retrieve arbitrary metadata. They are not queryable and should be
* preserved when modifying objects.
*
* More info: http://kubernetes.io/docs/user-guide/annotations
* More info: https://kubernetes.io/docs/user-guide/annotations
*/
annotations?: Partial<Record<string, string>>;
@ -136,7 +136,7 @@ export interface BaseKubeJsonApiObjectMetadata<Namespaced extends KubeObjectScop
* Map of string keys and values that can be used to organize and categorize (scope and select)
* objects. May match selectors of replication controllers and services.
*
* More info: http://kubernetes.io/docs/user-guide/labels
* More info: https://kubernetes.io/docs/user-guide/labels
*/
labels?: Partial<Record<string, string>>;
@ -154,7 +154,7 @@ export interface BaseKubeJsonApiObjectMetadata<Namespaced extends KubeObjectScop
* resources may allow a client to request the generation of an appropriate name automatically.
* Name is primarily intended for creation idempotence and configuration definition.
*
* More info: http://kubernetes.io/docs/user-guide/identifiers#names
* More info: https://kubernetes.io/docs/user-guide/identifiers#names
*/
readonly name: string;
@ -162,7 +162,7 @@ export interface BaseKubeJsonApiObjectMetadata<Namespaced extends KubeObjectScop
* Namespace defines the space within which each name must be unique. An empty namespace is
* equivalent to the "default" namespace, but "default" is the canonical representation. Not all
* objects are required to be scoped to a namespace - the value of this field for those objects
* will be empty. Must be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces
* will be empty. Must be a DNS_LABEL. Cannot be updated. More info: https://kubernetes.io/docs/user-guide/namespaces
*/
readonly namespace?: ScopedNamespace<Namespaced>;
@ -196,7 +196,7 @@ export interface BaseKubeJsonApiObjectMetadata<Namespaced extends KubeObjectScop
* server on successful creation of a resource and is not allowed to change on PUT operations.
* Populated by the system.
*
* More info: http://kubernetes.io/docs/user-guide/identifiers#uids
* More info: https://kubernetes.io/docs/user-guide/identifiers#uids
*/
readonly uid?: string;

View File

@ -8,3 +8,7 @@ export interface RequestChannel<Request, Response> {
_requestSignature?: Request; // used only to mark `Request` as "used"
_responseSignature?: Response; // used only to mark `Response` as "used"
}
export const getRequestChannel = <Request, Response>(id: string): RequestChannel<Request, Response> => ({
id,
});

View File

@ -9,11 +9,11 @@ import lensAuthenticatedFetchInjectable from "../fetch/lens-authed-fetch.injecta
const requestAppVersionInjectable = getInjectable({
id: "request-app-version",
instantiate: (di) => {
const lensAuthenticatedFetch = di.inject(lensAuthenticatedFetchInjectable);
const fetch = di.inject(lensAuthenticatedFetchInjectable);
const lensProxyPort = di.inject(lensProxyPortInjectable);
return async () => {
const response = await lensAuthenticatedFetch(`http://127.0.0.1:${lensProxyPort.get()}/version`);
const response = await fetch(`https://127.0.0.1:${lensProxyPort.get()}/version`);
const body = await response.json() as { version: string };
return body.version;

View File

@ -16,7 +16,7 @@ export default getGlobalOverride(applicationInformationInjectable, () => ({
bundledKubectlVersion: "1.23.3",
bundledHelmVersion: "3.7.2",
sentryDsn: "",
contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src https://*.localhost:*/; img-src * data:",
welcomeRoute: "/welcome",
extensions: [],
},

View File

@ -20,7 +20,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
const currentClusterServerUrl = "https://localhost";
const nonCurrentClusterServerUrl = "http://localhost";
const nonCurrentClusterServerUrl = "https://localhost";
const multiClusterConfig = `
apiVersion: v1
clusters:
@ -48,7 +48,7 @@ users:
token: kubeconfig-user-q4lm4:xxxyyyy
`;
const singleClusterServerUrl = "http://localhost";
const singleClusterServerUrl = "https://localhost";
const singleClusterConfig = `
apiVersion: v1
clusters:

View File

@ -146,7 +146,7 @@ describe("add custom helm repository in preferences", () => {
const urlInput = rendered.getByTestId("custom-helm-repository-url-input");
fireEvent.change(urlInput, { target: { value: "http://some.url" }});
fireEvent.change(urlInput, { target: { value: "https://some.url" }});
});
it("renders", () => {
@ -170,7 +170,7 @@ describe("add custom helm repository in preferences", () => {
it("adds the repository", () => {
expect(execFileMock).toHaveBeenCalledWith(
"some-helm-binary-path",
["repo", "add", "some-custom-repository", "http://some.url"],
["repo", "add", "some-custom-repository", "https://some.url"],
{
maxBuffer: 34359738368,
env: {},
@ -224,7 +224,7 @@ describe("add custom helm repository in preferences", () => {
await execFileMock.resolveSpecific(
[
"some-helm-binary-path",
["repo", "add", "some-custom-repository", "http://some.url"],
["repo", "add", "some-custom-repository", "https://some.url"],
],
{
callWasSuccessful: true,
@ -365,7 +365,7 @@ describe("add custom helm repository in preferences", () => {
"repo",
"add",
"some-custom-repository",
"http://some.url",
"https://some.url",
"--insecure-skip-tls-verify",
"--username",
"some-username",

View File

@ -23,7 +23,7 @@ const NonInjectedHttpProxyUrl = observer(
<SubTitle title="HTTP Proxy" />
<Input
theme="round-black"
placeholder="Type HTTP proxy url (example: http://proxy.acme.org:8080)"
placeholder="Type HTTP proxy url (example: https://proxy.acme.org:8080)"
value={proxy}
onChange={(v) => setProxy(v)}
onBlur={() => (userStore.httpsProxy = proxy)}

View File

@ -132,7 +132,7 @@ describe("opening application window using tray", () => {
});
it("starts loading of content for the application window", () => {
expect(callForApplicationWindowHtmlMock).toHaveBeenCalledWith("http://localhost:42");
expect(callForApplicationWindowHtmlMock).toHaveBeenCalledWith("https://localhost:42");
});
describe("given static HTML of application window has not resolved yet, when opening from tray again", () => {

View File

@ -108,7 +108,7 @@ describe("ContextHandler", () => {
id: "some-cluster-id",
kubeConfigPath: "/some/path/to/kubeconfig",
}, {
clusterServerUrl: "http://localhost:81",
clusterServerUrl: "https://localhost:81",
});
});

View File

@ -174,7 +174,7 @@ describe("kubeconfig manager tests", () => {
describe("when writing out new proxy kubeconfig resolves", () => {
beforeEach(async () => {
await writeFileMock.resolveSpecific(
["/some-directory-for-temp/kubeconfig-foo", "apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: minikube\nclusters:\n - name: minikube\n cluster:\n server: http://127.0.0.1:9191/foo\ncontexts:\n - name: minikube\n context:\n cluster: minikube\n user: proxy\nusers:\n - name: proxy\n user: {}\n"],
["/some-directory-for-temp/kubeconfig-foo", "apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: minikube\nclusters:\n - name: minikube\n cluster:\n server: https://127.0.0.1:9191/foo\ncontexts:\n - name: minikube\n context:\n cluster: minikube\n user: proxy\nusers:\n - name: proxy\n user: {}\n"],
);
});
@ -300,7 +300,7 @@ describe("kubeconfig manager tests", () => {
describe("when writing out new proxy kubeconfig resolves", () => {
beforeEach(async () => {
await writeFileMock.resolveSpecific(
["/some-directory-for-temp/kubeconfig-foo", "apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: minikube\nclusters:\n - name: minikube\n cluster:\n server: http://127.0.0.1:9191/foo\ncontexts:\n - name: minikube\n context:\n cluster: minikube\n user: proxy\nusers:\n - name: proxy\n user: {}\n"],
["/some-directory-for-temp/kubeconfig-foo", "apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: minikube\nclusters:\n - name: minikube\n cluster:\n server: https://127.0.0.1:9191/foo\ncontexts:\n - name: minikube\n context:\n cluster: minikube\n user: proxy\nusers:\n - name: proxy\n user: {}\n"],
);
});

View File

@ -25,7 +25,7 @@ const k8sRequestInjectable = getInjectable({
path: string,
options: RequestPromiseOptions = {},
) => {
const kubeProxyUrl = `http://localhost:${lensProxyPort.get()}${apiKubePrefix}`;
const kubeProxyUrl = `https://localhost:${lensProxyPort.get()}${apiKubePrefix}`;
options.headers ??= {};
options.json ??= true;

View File

@ -11,7 +11,7 @@ const apiBaseServerAddressInjectable = getInjectable({
instantiate: (di) => {
const lensProxyPort = di.inject(lensProxyPortInjectable);
return `http://127.0.0.1:${lensProxyPort.get()}`;
return `https://127.0.0.1:${lensProxyPort.get()}`;
},
injectionToken: apiBaseServerAddressInjectionToken,
});

View File

@ -15,6 +15,7 @@ import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import writeFileInjectable from "../../common/fs/write-file.injectable";
import removePathInjectable from "../../common/fs/remove.injectable";
import authHeaderValueInjectable from "../lens-proxy/auth-header-value.injectable";
import lensProxyCertificateInjectable from "../lens-proxy/certificate.injectable";
export interface KubeConfigManagerInstantiationParameter {
cluster: Cluster;
@ -31,6 +32,7 @@ const createKubeconfigManagerInjectable = getInjectable({
logger: di.inject(loggerInjectable),
lensProxyPort: di.inject(lensProxyPortInjectable),
authHeaderValue: di.inject(authHeaderValueInjectable),
lensProxyCertificate: di.inject(lensProxyCertificateInjectable),
joinPaths: di.inject(joinPathsInjectable),
getDirnameOfPath: di.inject(getDirnameOfPathInjectable),
removePath: di.inject(removePathInjectable),

View File

@ -16,12 +16,14 @@ import type { PathExists } from "../../common/fs/path-exists.injectable";
import type { RemovePath } from "../../common/fs/remove.injectable";
import type { WriteFile } from "../../common/fs/write-file.injectable";
import { lensAuthenticationHeader } from "../../common/vars/auth-header";
import type { SelfSignedCert } from "selfsigned";
export interface KubeconfigManagerDependencies {
readonly directoryForTemp: string;
readonly logger: Logger;
readonly lensProxyPort: { get: () => number };
readonly authHeaderValue: string;
readonly lensProxyCertificate: SelfSignedCert;
joinPaths: JoinPaths;
getDirnameOfPath: GetDirnameOfPath;
pathExists: PathExists;
@ -108,7 +110,9 @@ export class KubeconfigManager {
clusters: [
{
name: contextName,
server: `http://127.0.0.1:${this.dependencies.lensProxyPort.get()}/${this.cluster.id}?${searchParams}`,
caData: Buffer.from(this.dependencies.lensProxyCertificate.cert).toString("base64"),
server: `https://127.0.0.1:${this.dependencies.lensProxyPort.get()}/${this.cluster.id}?${searchParams}`,
skipTLSVerify: false,
},
],
users: [

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { generate } from "selfsigned";
import { lensProxyCertificateInjectionToken } from "../../common/certificate/token";
const lensProxyCertificateInjectable = getInjectable({
id: "lens-proxy-certificate",
instantiate: () => generate([
{ name: "commonName", value: "Lens Certificate Authority" },
{ name: "organizationName", value: "Lens" },
], {
keySize: 2048,
algorithm: "sha256",
days: 365,
extensions: [
{
name: "basicConstraints",
cA: true,
},
{
name: "subjectAltName",
altNames: [
{ type: 2, value: "*.localhost" },
{ type: 2, value: "localhost" },
{ type: 7, ip: "127.0.0.1" },
],
},
],
}),
injectionToken: lensProxyCertificateInjectionToken,
});
export default lensProxyCertificateInjectable;

View File

@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { lensProxyCertificateChannel } from "../../common/certificate/channel";
import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens";
import lensProxyCertificateInjectable from "./certificate.injectable";
const lensProxyCertificateHandlerInjectable = getRequestChannelListenerInjectable({
channel: lensProxyCertificateChannel,
handler: (di) => {
const cert = di.inject(lensProxyCertificateInjectable);
return () => cert;
},
});
export default lensProxyCertificateHandlerInjectable;

View File

@ -14,6 +14,7 @@ import contentSecurityPolicyInjectable from "../../common/vars/content-security-
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
import loggerInjectable from "../../common/logger.injectable";
import authHeaderValueInjectable from "./auth-header-value.injectable";
import lensProxyCertificateInjectable from "./certificate.injectable";
const lensProxyInjectable = getInjectable({
id: "lens-proxy",
@ -29,6 +30,7 @@ const lensProxyInjectable = getInjectable({
emitAppEvent: di.inject(emitAppEventInjectable),
logger: di.inject(loggerInjectable),
authHeaderValue: di.inject(authHeaderValueInjectable),
certificate: di.inject(lensProxyCertificateInjectable),
}),
});

View File

@ -4,7 +4,8 @@
*/
import net from "net";
import http from "http";
import type http from "http";
import https from "https";
import type httpProxy from "http-proxy";
import { apiPrefix, apiKubePrefix } from "../../common/vars";
import type { ClusterContextHandler } from "../context-handler/context-handler";
@ -20,6 +21,7 @@ import { lensAuthenticationHeader } from "../../common/vars/auth-header";
import { contentTypes } from "../router/router-content-types";
import { writeServerResponseFor } from "../router/write-server-response";
import { URL } from "url";
import type { SelfSignedCert } from "selfsigned";
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined;
@ -36,13 +38,14 @@ interface Dependencies {
readonly contentSecurityPolicy: string;
readonly logger: Logger;
readonly authHeaderValue: string;
readonly certificate: SelfSignedCert;
}
const watchParam = "watch";
const followParam = "follow";
export function isLongRunningRequest(reqUrl: string) {
const url = new URL(reqUrl, "http://localhost");
const url = new URL(reqUrl, "https://localhost");
return getBoolean(url.searchParams, watchParam) || getBoolean(url.searchParams, followParam);
}
@ -71,16 +74,22 @@ export class LensProxy {
protected readonly retryCounters = new Map<string, number>();
constructor(private readonly dependencies: Dependencies) {
this.configureProxy(dependencies.proxy);
this.configureProxy(this.dependencies.proxy);
this.proxyServer = http.createServer((req, res) => {
this.handleRequest(req as ServerIncomingMessage, res);
});
this.proxyServer = https.createServer(
{
key: this.dependencies.certificate.private,
cert: this.dependencies.certificate.cert,
},
(req, res) => {
this.handleRequest(req as ServerIncomingMessage, res);
},
);
this.proxyServer
.on("upgrade", (req: ServerIncomingMessage, socket: net.Socket, head: Buffer) => {
const cluster = this.dependencies.getClusterForRequest(req);
const url = new URL(req.url, "http://localhost");
const url = new URL(req.url, "https://localhost");
if (url.searchParams.get(lensAuthenticationHeader) !== this.dependencies.authHeaderValue) {
this.dependencies.logger.warn(`[LENS-PROXY]: Request from url=${req.url} missing authentication`);

View File

@ -79,7 +79,7 @@ const routeRequestInjectable = getInjectable({
const getRequest = getRequestWith(di);
return async (cluster, req, res) => {
const url = new URL(req.url, "http://localhost");
const url = new URL(req.url, "https://localhost");
const path = url.pathname;
const method = req.method.toLowerCase();
const matchingRoute = router.route(method, path);

View File

@ -14,7 +14,7 @@ const devStaticFileRouteHandlerInjectable = getInjectable({
instantiate: (di) => {
const proxy = httpProxy.createProxy();
const appName = di.inject(appNameInjectable);
const proxyTarget = `http://127.0.0.1:${webpackDevServerPort}`;
const proxyTarget = `https://127.0.0.1:${webpackDevServerPort}`;
return async ({ raw: { req, res }}: LensApiRequest<"/{path*}">): Promise<RouteResponse<Buffer>> => {
if (req.url === "/" || !req.url) {

View File

@ -33,7 +33,7 @@ const createApplicationWindowInjectable = getInjectable({
defaultHeight: 900,
defaultWidth: 1440,
getContentSource: () => ({
url: `http://localhost:${lensProxyPort.get()}`,
url: `https://localhost:${lensProxyPort.get()}`,
}),
resizable: true,
windowFrameUtilitiesAreShown: isMac,

View File

@ -14,6 +14,8 @@ import lensResourcesDirInjectable from "../../../../common/vars/lens-resources-d
import isLinuxInjectable from "../../../../common/vars/is-linux.injectable";
import applicationInformationInjectable from "../../../../common/vars/application-information.injectable";
import pathExistsSyncInjectable from "../../../../common/fs/path-exists-sync.injectable";
import lensProxyCertificateInjectable from "../../../lens-proxy/certificate.injectable";
import { timingSafeEqual, X509Certificate } from "crypto";
export type ElectronWindowTitleBarStyle = "hiddenInset" | "hidden" | "default" | "customButtonsOnHover";
@ -56,6 +58,8 @@ const createElectronWindowInjectable = getInjectable({
const isLinux = di.inject(isLinuxInjectable);
const applicationInformation = di.inject(applicationInformationInjectable);
const pathExistsSync = di.inject(pathExistsSyncInjectable);
const lensProxyCertificate = di.inject(lensProxyCertificateInjectable);
const lensProxyCert = new X509Certificate(lensProxyCertificate.cert);
return (configuration) => {
const applicationWindowState = di.inject(
@ -123,6 +127,13 @@ const createElectronWindowInjectable = getInjectable({
.webContents.on("dom-ready", () => {
configuration.onDomReady?.();
})
.on("certificate-error", (event, url, error, certificate, shouldBeTrusted) => {
const cert = new X509Certificate(certificate.data);
const shouldTrustCert = cert.raw.length === lensProxyCert.raw.length
&& timingSafeEqual(cert.raw, lensProxyCert.raw);
shouldBeTrusted(shouldTrustCert);
})
.on("did-fail-load", (_event, code, desc) => {
logger.error(
`[CREATE-ELECTRON-WINDOW]: Failed to load window "${configuration.id}"`,

View File

@ -4,7 +4,7 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { lensAuthenticationChannel } from "../../common/auth/channel";
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/tokens";
import requestFromChannelInjectable from "../utils/channel/request-from-channel.injectable";
import authHeaderValueStateInjectable from "./auth-header-state.injectable";

View File

@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { lensProxyCertificateInjectionToken } from "../../common/certificate/token";
import lensProxyCertificateStateInjectable from "./state.injectable";
const lensProxyCertificateInjectable = getInjectable({
id: "lens-proxy-certificate",
instantiate: (di) => di.inject(lensProxyCertificateStateInjectable).get(),
injectionToken: lensProxyCertificateInjectionToken,
});
export default lensProxyCertificateInjectable;

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { evenBeforeFrameStartsInjectionToken } from "../before-frame-starts/tokens";
import requestLensProxyCertificateInjectable from "./request.injectable";
import lensProxyCertificateStateInjectable from "./state.injectable";
const initLensProxyCertificateStateInjectable = getInjectable({
id: "init-lens-proxy-certificate-state",
instantiate: (di) => ({
id: "init-lens-proxy-certificate-state",
run: async () => {
const lensProxyCertificateState = di.inject(lensProxyCertificateStateInjectable);
const requestLensProxyCertificate = di.inject(requestLensProxyCertificateInjectable);
lensProxyCertificateState.set(await requestLensProxyCertificate());
},
}),
injectionToken: evenBeforeFrameStartsInjectionToken,
});
export default initLensProxyCertificateStateInjectable;

View File

@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { lensProxyCertificateChannel } from "../../common/certificate/channel";
import requestFromChannelInjectable from "../utils/channel/request-from-channel.injectable";
const requestLensProxyCertificateInjectable = getInjectable({
id: "request-lens-proxy-certificate",
instantiate: (di) => {
const requestFromChannel = di.inject(requestFromChannelInjectable);
return () => requestFromChannel(lensProxyCertificateChannel);
},
});
export default requestLensProxyCertificateInjectable;

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { SelfSignedCert } from "selfsigned";
const lensProxyCertificateStateInjectable = getInjectable({
id: "lens-proxy-certificate-state",
instantiate: () => {
let state: SelfSignedCert | undefined = undefined;
return {
get: () => {
if (!state) {
throw new Error("Tried to use lensProxyCertificate before initialization");
}
return state;
},
set: (cert: SelfSignedCert) => {
if (state) {
throw new Error("Tried to initialize lensProxyCertificate more than once");
}
state = cert;
},
};
},
});
export default lensProxyCertificateStateInjectable;

View File

@ -21,7 +21,7 @@ export const HelmChartIcon = ({
if (!icon || failedToLoad) {
return (
<div className={className}>
<svg viewBox="0 0 722.8 702" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 722.8 702" xmlns="https://www.w3.org/2000/svg">
<g fill="currentColor">
<path d="m318 299.5c2.1 1.6 4.8 2.5 7.6 2.5 6.9 0 12.6-5.5 12.9-12.3l.3-.2 4.3-76.7c-5.2.6-10.4 1.5-15.6 2.7-28.5 6.5-53.2 20.5-72.6 39.5l62.9 44.6z"/>
<path d="m309.5 411.9c-1.4-5.9-6.6-9.9-12.4-10-.8 0-1.7.1-2.5.2l-.1-.2-75.5 12.8c11.7 32.2 33.4 58.5 60.8 76.1l29.2-70.7-.2-.3c1.1-2.4 1.4-5.2.7-7.9z"/>

View File

@ -48,7 +48,7 @@ export class ClusterProxySetting extends React.Component<ClusterProxySettingProp
value={this.proxy}
onChange={this.onChange}
onBlur={this.save}
placeholder="http://<address>:<port>"
placeholder="https://<address>:<port>"
validators={this.proxy ? InputValidators.isUrl : undefined}
/>
<small className="hint">

View File

@ -35,14 +35,14 @@ describe("<Icon> href technical tests", () => {
const result = render((
<Icon
data-testid="my-icon"
href="http://localhost"
href="https://localhost"
/>
));
const icon = result.queryByTestId("my-icon");
expect(icon).toBeInTheDocument();
expect(icon).toHaveAttribute("href", "http://localhost");
expect(icon).toHaveAttribute("href", "https://localhost");
expect(logger.warn).not.toBeCalled();
});

View File

@ -27,7 +27,7 @@ describe("input validation tests", () => {
it.each([
"https://github-production-registry-package-file-4f11e5.s3.amazonaws.com/307985088/68bbbf00-309f-11eb-8457-a15e4efe9e77?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20201127%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201127T123754Z&X-Amz-Expires=300&X-Amz-Signature=9b8167f00685a20d980224d397892195abc187cdb2934cefb79edcd7ec600f78&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=0&response-content-disposition=filename%3Dstarboard-lens-extension-0.0.1-alpha.1-npm.tgz&response-content-type=application%2Foctet-stream",
"http://www.google.com",
"https://www.google.com",
])("Given '%s' is a valid url, emailOrUrl matches", (input) => {
expect(emailOrUrl.validate(input)).toBe(true);
});
@ -62,7 +62,7 @@ describe("input validation tests", () => {
it.each([
"https://github-production-registry-package-file-4f11e5.s3.amazonaws.com/307985088/68bbbf00-309f-11eb-8457-a15e4efe9e77?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20201127%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201127T123754Z&X-Amz-Expires=300&X-Amz-Signature=9b8167f00685a20d980224d397892195abc187cdb2934cefb79edcd7ec600f78&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=0&response-content-disposition=filename%3Dstarboard-lens-extension-0.0.1-alpha.1-npm.tgz&response-content-type=application%2Foctet-stream",
"http://www.google.com",
"https://www.google.com",
])("Given '%s' is a valid url, emailOrUrl matches", async (input) => {
try {
await emailOrUrl.validate(input);

View File

@ -11,7 +11,7 @@ const apiBaseServerAddressInjectable = getInjectable({
instantiate: (di) => {
const { port } = di.inject(windowLocationInjectable);
return `http://127.0.0.1:${port}`;
return `https://127.0.0.1:${port}`;
},
injectionToken: apiBaseServerAddressInjectionToken,
});

View File

@ -25,7 +25,7 @@ const apiKubeInjectable = getInjectable({
const lensAuthenticationHeaderValue = di.inject(lensAuthenticationHeaderValueInjectionToken);
const apiKube = createKubeJsonApi({
serverAddress: `http://127.0.0.1:${port}`,
serverAddress: `https://127.0.0.1:${port}`,
apiBase: apiKubePrefix,
debug: isDevelopment,
}, {