diff --git a/src/app/components/select/colored/interfaces/colored-select-option.interface.ts b/src/app/components/select/colored/interfaces/colored-select-option.interface.ts index 98ef2a94..a1c08fa4 100644 --- a/src/app/components/select/colored/interfaces/colored-select-option.interface.ts +++ b/src/app/components/select/colored/interfaces/colored-select-option.interface.ts @@ -2,5 +2,6 @@ export type ColoredSelectOption = { id: string; label: string; url: string; + authority: string; color: string; }; diff --git a/src/app/hooks/protocols/grpc/prepare-request.ts b/src/app/hooks/protocols/grpc/prepare-request.ts index d7857eb1..bfb5843c 100644 --- a/src/app/hooks/protocols/grpc/prepare-request.ts +++ b/src/app/hooks/protocols/grpc/prepare-request.ts @@ -1,18 +1,20 @@ -import { - GrpcClientRequestOptions, - GrpcMethodType, - GrpcOptions, - GrpcTlsConfig, - GrpcTlsType, -} from '@core/types'; -import { Collection, CollectionType, GrpcTab, TlsPreset } from '@storage'; +import { GrpcClientRequestOptions, GrpcMethodType, GrpcOptions, GrpcTlsConfig, GrpcTlsType } from "@core/types"; +import { Collection, CollectionType, GrpcTab, TlsPreset } from "@storage"; function getRequestAddress(tab: GrpcTab): string { if (tab.data.url && tab.data.url.length > 0) { return tab.data.url; } - throw new Error('Address is empty.'); + throw new Error("Address is empty."); +} + +function getRequestAuthority(tab: GrpcTab): string | undefined { + if (tab.data.authority && tab.data.authority.length > 0) { + return tab.data.authority; + } + + return undefined; } export function getTlsOptions(presets: TlsPreset[], id?: string): GrpcTlsConfig { @@ -43,6 +45,7 @@ export function getOptions( serviceName: service.name, methodName: method.name, address: getRequestAddress(tab), + authorityOverride: getRequestAuthority(tab), tls, }, ]; @@ -53,7 +56,7 @@ export function getOptions( export function parseRequest(tab: GrpcTab): Record { try { - const request = JSON.parse(tab.data.requestTabs.request.value?.trim() || '{}'); + const request = JSON.parse(tab.data.requestTabs.request.value?.trim() || "{}"); return request; } catch (error) { @@ -63,7 +66,7 @@ export function parseRequest(tab: GrpcTab): Record): Record { try { - const metadata = JSON.parse(tab.data.requestTabs.metadata.value?.trim() || '{}'); + const metadata = JSON.parse(tab.data.requestTabs.metadata.value?.trim() || "{}"); return metadata; } catch (error) { diff --git a/src/app/pages/shortcuts/hooks/use-environment-actions.tsx b/src/app/pages/shortcuts/hooks/use-environment-actions.tsx index 1870b531..900abf2e 100644 --- a/src/app/pages/shortcuts/hooks/use-environment-actions.tsx +++ b/src/app/pages/shortcuts/hooks/use-environment-actions.tsx @@ -16,6 +16,7 @@ export function useEnvironmentActions() { name: environment.label, keywords: environment.label, subtitle: environment.url, + authority: environment.authority, parent: 'environment', icon: ( = ({ - onSubmit = () => {}, + onSubmit = () => { }, id, defaultValues, }) => { @@ -68,6 +68,17 @@ export const EnvironmentForm: React.FC = ({ color={errors.url ? 'error' : 'default'} {...register('url', { required: true })} /> + + ); diff --git a/src/app/pages/tabs-container/collection-types/grpc/send-header/send-header.basic.tsx b/src/app/pages/tabs-container/collection-types/grpc/send-header/send-header.basic.tsx index ebc4a25f..3cd7a9a3 100644 --- a/src/app/pages/tabs-container/collection-types/grpc/send-header/send-header.basic.tsx +++ b/src/app/pages/tabs-container/collection-types/grpc/send-header/send-header.basic.tsx @@ -45,6 +45,7 @@ export const SendHeader: React.FC) => { - updateGrpcTabData(tab.id, { - environmentId: undefined, - url: e.target.value, - }); + if (tab.data.authority) { + updateGrpcTabData(tab.id, { + environmentId: undefined, + authority: e.target.value, + }); + } else { + const urlParts = e.target.value.split("/"); + if (urlParts.length > 1 && urlParts[1].trim().length > 0) { + updateGrpcTabData(tab.id, { + environmentId: undefined, + url: urlParts[0].trim(), + authority: urlParts[1].trim(), + }); + } else { + updateGrpcTabData(tab.id, { + environmentId: undefined, + url: e.target.value, + }); + } + } }; const handleCreateEnvironmentModalSubmit = (environment: Environment) => { @@ -123,8 +140,9 @@ export const SendHeader: React.FC { protocol: GrpcProtocol; environmentId?: string; url?: string; + authority?: string; tlsId?: string; requestTabs: { diff --git a/src/core/clients/grpc/grpc-client/grpc-client.ts b/src/core/clients/grpc/grpc-client/grpc-client.ts index 43ee9dc6..1f6ecad5 100644 --- a/src/core/clients/grpc/grpc-client/grpc-client.ts +++ b/src/core/clients/grpc/grpc-client/grpc-client.ts @@ -7,12 +7,12 @@ import type { MetadataValue, ServerErrorResponse, ServiceClientConstructor, -} from '@grpc/grpc-js'; -import * as grpc from '@grpc/grpc-js'; -import type { PackageDefinition } from '@grpc/proto-loader'; -import * as fs from 'fs'; -import * as _ from 'lodash'; -import { performance } from 'perf_hooks'; +} from "@grpc/grpc-js"; +import * as grpc from "@grpc/grpc-js"; +import type { PackageDefinition } from "@grpc/proto-loader"; +import * as fs from "fs"; +import * as _ from "lodash"; +import { performance } from "perf_hooks"; import { GrpcChannelOptions, @@ -23,11 +23,11 @@ import { GrpcTlsType, isInsecureTlsConfig, isMutualTlsConfig, -} from '../interfaces'; -import { MetadataParser } from './metadata-parser'; +} from "../interfaces"; +import { MetadataParser } from "./metadata-parser"; function instanceOfServiceClientConstructor(object: any): object is ServiceClientConstructor { - return 'serviceName' in object; + return "serviceName" in object; } export class GrpcClient { @@ -54,16 +54,17 @@ export class GrpcClient { const channelOptions: ChannelOptions = {}; if (options?.sslTargetNameOverride) { - channelOptions['grpc.ssl_target_name_override'] = options.sslTargetNameOverride; + channelOptions["grpc.ssl_target_name_override"] = options.sslTargetNameOverride; + } + if (options?.authorityOverride) { + channelOptions["grpc.ssl_target_name_override"] = options.authorityOverride; + channelOptions["grpc.default_authority"] = options.authorityOverride; } return channelOptions; } - private static loadClient( - packageDefinition: PackageDefinition, - requestOptions: GrpcClientRequestOptions - ) { + private static loadClient(packageDefinition: PackageDefinition, requestOptions: GrpcClientRequestOptions) { const ast = grpc.loadPackageDefinition(packageDefinition); const ServiceClient = _.get(ast, requestOptions.serviceName); @@ -71,20 +72,20 @@ export class GrpcClient { const client = new ServiceClient( requestOptions.address, this.getChannelCredentials(requestOptions.tls), - this.getChannelOptions(requestOptions.tls.channelOptions) + this.getChannelOptions({ + ...requestOptions.tls.channelOptions, + authorityOverride: requestOptions.authorityOverride, + }) ); - if ( - client[requestOptions.methodName] && - typeof client[requestOptions.methodName] === 'function' - ) { + if (client[requestOptions.methodName] && typeof client[requestOptions.methodName] === "function") { return client; } - throw new Error('No method definition'); + throw new Error("No method definition"); } - throw new Error('No service definition'); + throw new Error("No service definition"); } static async invokeUnaryRequest( @@ -147,14 +148,14 @@ export class GrpcClient { metadata ? MetadataParser.parse(metadata) : new grpc.Metadata(), (error: ServerErrorResponse, response: Record) => { if (error) { - return call.emit('error', { + return call.emit("error", { code: error.code, details: error.details, metadata: error.metadata?.toJSON(), }); } - return call.emit('data', response); + return call.emit("data", response); } ); diff --git a/src/core/clients/grpc/interfaces/client.interface.ts b/src/core/clients/grpc/interfaces/client.interface.ts index ca0b8a16..f494eece 100644 --- a/src/core/clients/grpc/interfaces/client.interface.ts +++ b/src/core/clients/grpc/interfaces/client.interface.ts @@ -1,7 +1,7 @@ export enum GrpcTlsType { - INSECURE = 'insecure', - SERVER_SIDE = 'server-side', - MUTUAL = 'mutual', + INSECURE = "insecure", + SERVER_SIDE = "server-side", + MUTUAL = "mutual", } export type GrpcTlsConfig = T extends GrpcTlsType.MUTUAL @@ -25,6 +25,8 @@ export interface GrpcChannelOptions { * If this parameter is specified and the underlying is not an SSL channel, it will just be ignored. */ sslTargetNameOverride?: string; + + authorityOverride?: string; } export interface GrpcServerSideTlsConfig { @@ -60,17 +62,15 @@ export interface GrpcClientRequestOptions { address: string; + authorityOverride?: string; + tls: GrpcTlsConfig; } -export function isInsecureTlsConfig( - config: GrpcTlsConfig -): config is GrpcTlsConfig { +export function isInsecureTlsConfig(config: GrpcTlsConfig): config is GrpcTlsConfig { return config.type === GrpcTlsType.INSECURE; } -export function isMutualTlsConfig( - config: GrpcTlsConfig -): config is GrpcTlsConfig { +export function isMutualTlsConfig(config: GrpcTlsConfig): config is GrpcTlsConfig { return config.type === GrpcTlsType.MUTUAL; }