Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions KeeperSdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@ export {
formatCreateGatewayOutput,
editGateway,
formatEditGatewayOutput,
removeGateway,
formatRemoveGatewayOutput,
setGatewayMaxInstances,
formatSetGatewayMaxInstancesOutput,
GatewayListFormat,
GatewayStatus,
GatewayConfigInitFormat,
Expand All @@ -678,6 +682,7 @@ export {
GATEWAY_LIST_VERBOSE_HEADERS,
getKeeperRouterBaseUrl,
webSafeUidFromBytes,
controllerUidsEqual,
toFiniteNumber,
formatTimestampMs,
parseGatewayVersionString,
Expand All @@ -686,6 +691,8 @@ export {
getKeeperRegionAbbreviation,
formatGatewayOneTimeToken,
findEnterpriseGatewayByUidOrName,
requireEnterpriseGatewayByUidOrName,
fetchEnterprisePamControllers,
groupOnlineGatewaysByControllerUid,
isKeeperRouterConnectionError,
} from './pam'
Expand All @@ -709,6 +716,10 @@ export type {
CreateGatewayResult,
EditGatewayInput,
EditGatewayResult,
RemoveGatewayInput,
RemoveGatewayResult,
SetGatewayMaxInstancesInput,
SetGatewayMaxInstancesResult,
GatewayJsonPoolInstance,
GatewayJsonEntry,
GatewaysJsonPayload,
Expand Down
20 changes: 20 additions & 0 deletions KeeperSdk/src/pam/PamManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import type {
FormattedGatewaysTable,
ListGatewaysOptions,
ListGatewaysResult,
RemoveGatewayInput,
RemoveGatewayResult,
RenderGatewaysAsciiTableOptions,
SetGatewayMaxInstancesInput,
SetGatewayMaxInstancesResult,
} from './gateway/gatewayTypes'

export type AuthProvider = () => Auth
Expand Down Expand Up @@ -49,6 +53,22 @@ export class PamManager {
return this.gatewayManager.formatEditGatewayOutput(result)
}

public async removeGateway(input: RemoveGatewayInput): Promise<RemoveGatewayResult> {
return this.gatewayManager.removeGateway(input)
}

public formatRemoveGatewayOutput(result: RemoveGatewayResult): string {
return this.gatewayManager.formatRemoveGatewayOutput(result)
}

public async setGatewayMaxInstances(input: SetGatewayMaxInstancesInput): Promise<SetGatewayMaxInstancesResult> {
return this.gatewayManager.setGatewayMaxInstances(input)
}

public formatSetGatewayMaxInstancesOutput(result: SetGatewayMaxInstancesResult): string {
return this.gatewayManager.formatSetGatewayMaxInstancesOutput(result)
}

public formatGatewaysTable(
result: ListGatewaysResult,
options: FormatGatewaysTableOptions = {}
Expand Down
22 changes: 22 additions & 0 deletions KeeperSdk/src/pam/gateway/GatewayManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { InMemoryStorage } from '../../storage/InMemoryStorage'
import { KeeperSdkError, ResultCodes } from '../../utils'
import { createGateway, formatCreateGatewayOutput } from './createGateway'
import { editGateway, formatEditGatewayOutput } from './editGateway'
import { removeGateway, formatRemoveGatewayOutput } from './removeGateway'
import { formatSetGatewayMaxInstancesOutput, setGatewayMaxInstances } from './setGatewayMaxInstances'
import {
formatGatewaysJson,
formatGatewaysOutput,
Expand All @@ -19,7 +21,11 @@ import type {
FormattedGatewaysTable,
ListGatewaysOptions,
ListGatewaysResult,
RemoveGatewayInput,
RemoveGatewayResult,
RenderGatewaysAsciiTableOptions,
SetGatewayMaxInstancesInput,
SetGatewayMaxInstancesResult,
} from './gatewayTypes'

export type AuthProvider = () => Auth
Expand Down Expand Up @@ -64,6 +70,22 @@ export class GatewayManager {
return formatEditGatewayOutput(result)
}

public async removeGateway(input: RemoveGatewayInput): Promise<RemoveGatewayResult> {
return removeGateway(this.requireAuth(), input)
}

public formatRemoveGatewayOutput(result: RemoveGatewayResult): string {
return formatRemoveGatewayOutput(result)
}

public async setGatewayMaxInstances(input: SetGatewayMaxInstancesInput): Promise<SetGatewayMaxInstancesResult> {
return setGatewayMaxInstances(this.requireAuth(), input)
}

public formatSetGatewayMaxInstancesOutput(result: SetGatewayMaxInstancesResult): string {
return formatSetGatewayMaxInstancesOutput(result)
}

public formatGatewaysTable(
result: ListGatewaysResult,
options: FormatGatewaysTableOptions = {}
Expand Down
4 changes: 1 addition & 3 deletions KeeperSdk/src/pam/gateway/createGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,10 @@ function buildCreateGatewayMessage(
tokenExpiresInMin: number,
isInitializedConfig: boolean
): string {
const base = `The one-time token was created in application [${appLabel}]. The new Gateway named ${gatewayName} will show up in the gateway list once it is initialized.`
if (isInitializedConfig) {
return `The one-time token was created in application [${appLabel}]. Use the initialized config in the Gateway. The new Gateway named ${gatewayName} will show up in the gateway list once it is initialized.`
}
return `${base} Token expires in ${tokenExpiresInMin} minutes.`
return `The one-time token was created in application [${appLabel}]. The new Gateway named ${gatewayName} will show up in the gateway list once it is initialized. Token expires in ${tokenExpiresInMin} minutes.`
}

export async function createGateway(
Expand Down Expand Up @@ -221,7 +220,6 @@ export async function createGateway(
? await initKsmConfigFromToken(oneTimeToken, host, configInit)
: oneTimeToken

// Automation: return only the OTT / initialized config string (Commander -r).
if (returnValue) {
return tokenOrConfig
}
Expand Down
32 changes: 10 additions & 22 deletions KeeperSdk/src/pam/gateway/editGateway.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { Auth, PAM } from '@keeper-security/keeperapi'
import { createInMessage, getControllers, normal64Bytes, PAM as PamProto } from '@keeper-security/keeperapi'
import type { Auth } from '@keeper-security/keeperapi'
import { modifyControllerMessage, normal64Bytes } from '@keeper-security/keeperapi'
import { EnterpriseDataInclude, EnterpriseDataManager } from '../../teams/enterpriseData'
import { applyDecryptedNodeNames, resolveParentNode } from '../../teams/teamUtils'
import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../../utils'
import { findEnterpriseGatewayByUidOrName, toFiniteNumber, webSafeUidFromBytes } from './gatewayHelpers'
import {
fetchEnterprisePamControllers,
requireEnterpriseGatewayByUidOrName,
toFiniteNumber,
webSafeUidFromBytes,
} from './gatewayHelpers'
import type { EditGatewayInput, EditGatewayResult } from './gatewayTypes'

function modifyControllerMessage(data: PAM.IPAMController) {
return createInMessage(data, 'pam/modify_controller', PamProto.PAMController)
}

function hasNodeArgument(nodeIdOrName: EditGatewayInput['nodeIdOrName']): boolean {
return (
nodeIdOrName !== undefined &&
Expand Down Expand Up @@ -73,21 +74,8 @@ export async function editGateway(auth: Auth, input: EditGatewayInput): Promise<
)
}

let controllers: PAM.IPAMController[]
try {
const response = await auth.executeRest(getControllers())
controllers = response.controllers ?? []
} catch (err) {
throw new KeeperSdkError(
`Failed to list enterprise gateways: ${extractErrorMessage(err)}`,
ResultCodes.PAM_GATEWAY_EDIT_FAILED
)
}

const gateway = findEnterpriseGatewayByUidOrName(controllers, gatewayUidOrName)
if (!gateway?.controllerUid?.length) {
throw new KeeperSdkError(`Gateway "${gatewayUidOrName}" not found.`, ResultCodes.PAM_GATEWAY_NOT_FOUND)
}
const controllers = await fetchEnterprisePamControllers(auth, ResultCodes.PAM_GATEWAY_EDIT_FAILED)
const gateway = requireEnterpriseGatewayByUidOrName(controllers, gatewayUidOrName)

const gatewayUid = webSafeUidFromBytes(gateway.controllerUid)
const previousName = gateway.controllerName || ''
Expand Down
51 changes: 40 additions & 11 deletions KeeperSdk/src/pam/gateway/gatewayHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import type { DRecord, PAM } from '@keeper-security/keeperapi'
import { getKeeperRouterUrl, webSafe64FromBytes } from '@keeper-security/keeperapi'
import type { Auth, DRecord, PAM } from '@keeper-security/keeperapi'
import { getControllers, getKeeperRouterUrl, webSafe64FromBytes } from '@keeper-security/keeperapi'
import type { InMemoryStorage } from '../../storage/InMemoryStorage'
import { VaultObjectKind } from '../../folders/folderHelpers'
import { getRecordTitle } from '../../records/RecordUtils'
import { KEEPER_PUBLIC_HOSTS, KeeperSdkError, ResultCodes } from '../../utils'
import { KEEPER_PUBLIC_HOSTS, KeeperSdkError, ResultCodes, extractErrorMessage } from '../../utils'
import {
APP_NOT_ACCESSIBLE_LABEL,
KSM_APP_RECORD_VERSION,
ROUTER_CONNECTION_ERROR_CODES,
type RouterConnectionErrorCode,
} from './gatewayConstants'
import type { GatewayVersionParts, KsmApplicationDisplayInfo, ResolvedKsmApplication } from './gatewayTypes'

type NetworkErrorLike = {
code?: string
errno?: string
message?: string
cause?: { code?: string }
}
import type {
GatewayVersionParts,
KsmApplicationDisplayInfo,
NetworkErrorLike,
ResolvedKsmApplication,
} from './gatewayTypes'

export function getKeeperRouterBaseUrl(host: string): string {
return getKeeperRouterUrl(host, '').replace(/\/$/, '')
Expand All @@ -28,6 +26,14 @@ export function webSafeUidFromBytes(bytes: Uint8Array | null | undefined): strin
return webSafe64FromBytes(bytes)
}

export function controllerUidsEqual(a: Uint8Array | null | undefined, b: Uint8Array | null | undefined): boolean {
if (!a || !b || a.length !== b.length) return false
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false
}
return true
}

export function toFiniteNumber(value: unknown): number {
if (value == null) return 0
if (typeof value === 'number') return Number.isFinite(value) ? value : 0
Expand Down Expand Up @@ -194,6 +200,29 @@ export function findEnterpriseGatewayByUidOrName(
})
}

export function requireEnterpriseGatewayByUidOrName(
controllers: readonly PAM.IPAMController[],
gatewayUidOrName: string
): PAM.IPAMController {
const gateway = findEnterpriseGatewayByUidOrName(controllers, gatewayUidOrName)
if (!gateway?.controllerUid?.length) {
throw new KeeperSdkError(`Gateway "${gatewayUidOrName}" not found.`, ResultCodes.PAM_GATEWAY_NOT_FOUND)
}
return gateway
}

export async function fetchEnterprisePamControllers(
auth: Auth,
failureResultCode: string
): Promise<PAM.IPAMController[]> {
try {
const response = await auth.executeRest(getControllers())
return response.controllers ?? []
} catch (err) {
throw new KeeperSdkError(`Failed to list enterprise gateways: ${extractErrorMessage(err)}`, failureResultCode)
}
}

export function groupOnlineGatewaysByControllerUid(
controllers: readonly PAM.IPAMOnlineController[]
): Map<string, PAM.IPAMOnlineController[]> {
Expand Down
33 changes: 33 additions & 0 deletions KeeperSdk/src/pam/gateway/gatewayTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export type CreateGatewayInput = {
application: string
tokenExpiresInMin?: number
configInit?: GatewayConfigInitFormatInput
/** When true, return only the OTT/config string (automation / -r). */
returnValue?: boolean
}

Expand Down Expand Up @@ -155,6 +156,31 @@ export type EditGatewayResult = {
message: string
}

export type RemoveGatewayInput = {
gatewayUidOrName: string
}

export type RemoveGatewayResult = {
success: boolean
found: boolean
gatewayUid?: string
gatewayName?: string
message: string
}

export type SetGatewayMaxInstancesInput = {
gatewayUidOrName: string
maxInstances: number
}

export type SetGatewayMaxInstancesResult = {
success: boolean
gatewayUid: string
gatewayName: string
maxInstances: number
message: string
}

export type GatewayJsonPoolInstance = {
instance_number: number
status: typeof GatewayStatus.Online
Expand Down Expand Up @@ -193,3 +219,10 @@ export type GatewaysJsonPayload = {
gateway_counts?: GatewayCounts
message?: string
}

export type NetworkErrorLike = {
code?: string
errno?: string
message?: string
cause?: { code?: string }
}
9 changes: 9 additions & 0 deletions KeeperSdk/src/pam/gateway/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export {

export { createGateway, formatCreateGatewayOutput } from './createGateway'
export { editGateway, formatEditGatewayOutput } from './editGateway'
export { removeGateway, formatRemoveGatewayOutput } from './removeGateway'
export { setGatewayMaxInstances, formatSetGatewayMaxInstancesOutput } from './setGatewayMaxInstances'

export { GatewayListFormat, GatewayStatus, GatewayConfigInitFormat } from './gatewayTypes'
export type {
Expand All @@ -33,6 +35,10 @@ export type {
CreateGatewayResult,
EditGatewayInput,
EditGatewayResult,
RemoveGatewayInput,
RemoveGatewayResult,
SetGatewayMaxInstancesInput,
SetGatewayMaxInstancesResult,
GatewayJsonPoolInstance,
GatewayJsonEntry,
GatewaysJsonPayload,
Expand All @@ -52,6 +58,7 @@ export {
export {
getKeeperRouterBaseUrl,
webSafeUidFromBytes,
controllerUidsEqual,
toFiniteNumber,
formatTimestampMs,
parseGatewayVersionString,
Expand All @@ -60,6 +67,8 @@ export {
getKeeperRegionAbbreviation,
formatGatewayOneTimeToken,
findEnterpriseGatewayByUidOrName,
requireEnterpriseGatewayByUidOrName,
fetchEnterprisePamControllers,
groupOnlineGatewaysByControllerUid,
isKeeperRouterConnectionError,
} from './gatewayHelpers'
17 changes: 3 additions & 14 deletions KeeperSdk/src/pam/gateway/listGateways.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Auth, PAM } from '@keeper-security/keeperapi'
import { getControllers, pamGetOnlineControllersMessage } from '@keeper-security/keeperapi'
import { pamGetOnlineControllersMessage } from '@keeper-security/keeperapi'
import type { InMemoryStorage } from '../../storage/InMemoryStorage'
import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../../utils'
import { EMPTY_GATEWAYS_MESSAGE, GATEWAY_LIST_DEFAULT_HEADERS, GATEWAY_LIST_VERBOSE_HEADERS } from './gatewayConstants'
import {
fetchEnterprisePamControllers,
formatTimestampMs,
getKeeperRouterBaseUrl,
getKsmApplicationDisplayInfo,
Expand Down Expand Up @@ -101,18 +102,6 @@ async function loadOnlineControllers(
}
}

async function loadEnterpriseControllers(auth: Auth): Promise<PAM.IPAMController[]> {
try {
const response = await auth.executeRest(getControllers())
return response.controllers ?? []
} catch (err) {
throw new KeeperSdkError(
`Failed to list enterprise gateways: ${extractErrorMessage(err)}`,
ResultCodes.PAM_GATEWAY_LIST_FAILED
)
}
}

function resolveConnectivityStatus(routerDown: boolean, connectedCount: number): GatewayListRow['status'] {
if (routerDown) return GatewayStatus.Unknown
if (connectedCount === 0) return GatewayStatus.Offline
Expand Down Expand Up @@ -243,7 +232,7 @@ export async function listGateways(
const online = await loadOnlineControllers(auth, force, routerHost)
if (online.abort) return online.abort

const enterpriseControllers = await loadEnterpriseControllers(auth)
const enterpriseControllers = await fetchEnterprisePamControllers(auth, ResultCodes.PAM_GATEWAY_LIST_FAILED)
if (!enterpriseControllers.length) {
return emptyListResult({
routerDown: online.routerDown,
Expand Down
Loading
Loading