Skip to content

Commit 2c767d3

Browse files
authored
Merge branch 'main' into kcli-bug-fixes
2 parents 20a1836 + fc1cc8a commit 2c767d3

41 files changed

Lines changed: 4169 additions & 20 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

KeeperSdk/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ Most examples call the shared `login()` helper, which attempts persistent login
429429

430430
See [`examples/sdk_example/README.md`](../examples/sdk_example/README.md) for the full command list.
431431

432+
Prefer an interactive shell over one-off scripts? See [`examples/repl`](../examples/repl/README.md)
433+
for a REPL that logs in once and runs vault commands (`ls`, `cd`, `get`, `find`, …) until you exit.
434+
432435
---
433436

434437
## Development Setup
@@ -467,6 +470,7 @@ keeper-sdk-javascript/
467470
├── keeperapi/ # @keeper-security/keeperapi
468471
└── examples/
469472
├── sdk_example/ # Runnable Node scripts (auth, records, folders, …)
473+
├── repl/ # Interactive vault shell
470474
├── print-vault-node/ # Additional Node sample
471475
└── print-vault-browser/ # Browser sample
472476
```

KeeperSdk/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

KeeperSdk/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@keeper-security/keeper-sdk-javascript",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "High-level wrapper for Keeper Security JavaScript SDK",
55
"repository": {
66
"type": "git",
@@ -24,7 +24,7 @@
2424
"prepublishOnly": "npm run build"
2525
},
2626
"dependencies": {
27-
"@keeper-security/keeperapi": "^18.1.1",
27+
"@keeper-security/keeperapi": "18.2.0",
2828
"@keeper-security/secrets-manager-core": "^17.5.0",
2929
"asmcrypto.js": "^2.3.2",
3030
"ts-node": "^10.7.0",

KeeperSdk/src/auth/ConsoleLogin.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,11 @@ async function syncVault(vault: KeeperVault): Promise<KeeperVault> {
341341
return vault
342342
}
343343

344+
export function closePrompt(): void {
345+
getReadlineManager().close()
346+
}
347+
344348
export function cleanup(vault: KeeperVault): void {
345349
vault.disconnect()
346-
getReadlineManager().close()
350+
closePrompt()
347351
}

KeeperSdk/src/auth/SessionManager.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ export class SessionManager implements SessionStorage {
8383
public createOnDeviceConfig(host: string): (deviceConfig: DeviceConfig) => Promise<void> {
8484
return async (deviceConfig: DeviceConfig) => {
8585
this.sessionDevices.set(host, { ...deviceConfig })
86+
await this.persistDeviceConfig(host, deviceConfig)
87+
}
88+
}
89+
90+
private async persistDeviceConfig(host: string, deviceConfig: DeviceConfig): Promise<void> {
91+
if (!deviceConfig.deviceToken || !deviceConfig.privateKey) return
92+
93+
const username = this._lastUsername
94+
if (!username) return
95+
96+
try {
97+
const parsed = await this.configLoader.load()
98+
const config: KeeperJsonConfig = parsed && Object.keys(parsed).length > 0 ? parsed : {}
99+
100+
config.device_token = Buffer.from(deviceConfig.deviceToken).toString('base64url')
101+
config.private_key = Buffer.from(deviceConfig.privateKey).toString('base64url')
102+
config.user = username
103+
config.server = host
104+
105+
await this.configLoader.save(config)
106+
this._keeperConfig = null
107+
this._deviceCache = null
108+
} catch (err) {
109+
logger.warn('Failed to persist device config:', extractErrorMessage(err))
86110
}
87111
}
88112

@@ -135,12 +159,15 @@ export class SessionManager implements SessionStorage {
135159
const device = (parsed.devices || []).find(
136160
(configDevice) => configDevice.device_token === user.last_device!.device_token
137161
)
138-
if (device?.server_info) {
139-
const serverInfo = device.server_info.find((entry) => entry.server === host)
140-
if (serverInfo) {
141-
serverInfo.clone_code = encodedCloneCode
142-
updated = true
162+
if (device) {
163+
device.server_info = device.server_info || []
164+
let serverInfo = device.server_info.find((entry) => entry.server === host)
165+
if (!serverInfo) {
166+
serverInfo = { server: host }
167+
device.server_info.push(serverInfo)
143168
}
169+
serverInfo.clone_code = encodedCloneCode
170+
updated = true
144171
}
145172
}
146173

KeeperSdk/src/auth/node/FileConfigLoader.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export class FileConfigLoader implements ConfigLoader {
2929

3030
async save(config: KeeperJsonConfig): Promise<void> {
3131
const configPath = path.join(this.configDir, 'config.json')
32+
await fs.mkdir(this.configDir, { recursive: true, mode: 0o700 })
3233
await fs.writeFile(configPath, JSON.stringify(config, null, 2), {
3334
mode: 0o600,
3435
})

KeeperSdk/src/index.ts

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type {
1616
ConfigurationServerConfig,
1717
ConfigurationDeviceConfig,
1818
} from './auth/SessionManager'
19-
export { login, cleanup, prompt, suppressLogs, loadKeeperConfig, resolveServer } from './auth/ConsoleLogin'
19+
export { login, cleanup, closePrompt, prompt, suppressLogs, loadKeeperConfig, resolveServer } from './auth/ConsoleLogin'
2020
export { connectSdkPlatform, getSdkPlatform, isSdkPlatformConnected } from './platform'
2121
export type { SdkPlatform, SdkReadline, SdkRuntime } from './platform'
2222
export type { SessionRestoreInput } from './auth/sessionRestore'
@@ -894,6 +894,67 @@ export {
894894
fetchEnterprisePamControllers,
895895
groupOnlineGatewaysByControllerUid,
896896
isKeeperRouterConnectionError,
897+
ConfigManager,
898+
listPamConfigurations,
899+
formatPamConfigurationsTable,
900+
renderPamConfigurationsAsciiTable,
901+
formatPamConfigurationsJson,
902+
formatPamConfigurationsOutput,
903+
createPamConfiguration,
904+
editPamConfiguration,
905+
removePamConfiguration,
906+
PamConfigListFormat,
907+
SUPPORTED_PAM_CONFIGURATION_RECORD_VERSIONS,
908+
PAM_CONFIGURATION_RECORD_TYPES,
909+
PAM_CONFIG_ENVIRONMENT_TO_RECORD_TYPE,
910+
PAM_CONFIG_ENVIRONMENTS,
911+
PAM_CONFIGURATION_FALLBACK_SCHEMA_FIELDS,
912+
PAM_RESOURCES_FIELD_TYPE,
913+
FILE_REF_FIELD_TYPE,
914+
SCHEDULE_FIELD_TYPE,
915+
DEFAULT_PAM_CONFIG_SCHEDULE_VALUE,
916+
EMPTY_PAM_CONFIGURATIONS_MESSAGE,
917+
PAM_CONFIG_LIST_DEFAULT_HEADERS,
918+
PAM_CONFIG_LIST_VERBOSE_HEADERS,
919+
PAM_CONFIG_DETAIL_LABELS,
920+
PAM_CONFIG_PERMISSION_DAG_KEYS,
921+
PAM_CONFIG_PERMISSION_FLAGS,
922+
PAM_CONFIG_PERMISSION_VALUES,
923+
isPamConfigurationRecordType,
924+
isPamConfigEnvironment,
925+
resolvePamConfigurationRecordType,
926+
isPamConfigurationRecord,
927+
isSupportedPamConfigurationRecordVersion,
928+
getPamConfigurationFields,
929+
parsePamResources,
930+
resolveSharedFolderName,
931+
findSharedFolderUidForRecord,
932+
listPamConfigurationRecords,
933+
getPamConfigurationDisplayName,
934+
normalizeFields,
935+
ensureScheduleField,
936+
mergeRecordFields,
937+
adjustPamConfigurationFields,
938+
seedPamConfigurationFieldsFromRecordTypeSoft,
939+
seedPamConfigurationFieldsFromRecordTypeStrict,
940+
readTypedRecordPayload,
941+
upsertPamResourcesField,
942+
resolveGatewayUidSoft,
943+
findPamConfigurationByUidOrTitle,
944+
resolveResourceRecordUidsToRemove,
945+
linkConfigurationController,
946+
hasPermissionsInput,
947+
convertPermissionValue,
948+
normalizePermissionValue,
949+
buildAllowedSettingsFromPermissions,
950+
applyPamConfigurationPermissions,
951+
isPamConfigurationInFolder,
952+
resolvePamConfigFolder,
953+
findPamConfigFolderForRecord,
954+
resolvePamConfigFolderTargetFromUid,
955+
resolvePamConfigFolderName,
956+
formatPamConfigFolderDisplay,
957+
placePamConfigurationInFolder,
897958
} from './pam'
898959
export type {
899960
ListGatewaysOptions,
@@ -923,6 +984,36 @@ export type {
923984
GatewayJsonEntry,
924985
GatewaysJsonPayload,
925986
KsmAppRecordVersion,
987+
PamConfigurationRecordType,
988+
PamConfigurationRecordVersion,
989+
PamConfigEnvironment,
990+
PamConfigPermissionFlag,
991+
PamConfigListFormatInput,
992+
ListPamConfigurationsOptions,
993+
PamResourcesInfo,
994+
PamConfigurationField,
995+
PamConfigurationListRow,
996+
PamConfigurationDetail,
997+
ListPamConfigurationsResult,
998+
FormattedPamConfigurationsTable,
999+
FormatPamConfigurationsTableOptions,
1000+
RenderPamConfigurationsAsciiTableOptions,
1001+
PamConfigurationJsonField,
1002+
PamConfigurationJsonEntry,
1003+
PamConfigurationsJsonPayload,
1004+
PamConfigurationRecordFieldInput,
1005+
PamConfigurationPermissionValue,
1006+
PamConfigurationPermissionsInput,
1007+
PamNetworkAllowedSettings,
1008+
CreatePamConfigurationInput,
1009+
CreatePamConfigurationResult,
1010+
EditPamConfigurationInput,
1011+
EditPamConfigurationResult,
1012+
RemovePamConfigurationInput,
1013+
RemovedPamConfiguration,
1014+
RemovePamConfigurationResult,
1015+
PamConfigFolderKind,
1016+
PamConfigFolderTarget,
9261017
} from './pam'
9271018

9281019
export type {

KeeperSdk/src/nestedShareFolders/nsfRecordTypes.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ export async function getNsfRecordTypeFields(auth: Auth, recordType: string): Pr
6060
const normalized = recordType.trim()
6161
if (!normalized || NSF_LEGACY_RECORD_TYPES.has(normalized)) return undefined
6262

63+
const lowered = normalized.toLowerCase()
6364
const types = await loadRecordTypes(auth)
6465
for (const entry of types) {
6566
if (!entry.content) continue
6667
const schema = parseRecordTypeSchema(entry.content)
67-
if (schema?.id === normalized && schema.fields?.length) {
68+
if (!schema?.id || !schema.fields?.length) continue
69+
if (schema.id === normalized || schema.id.toLowerCase() === lowered) {
6870
return schema.fields
6971
}
7072
}

KeeperSdk/src/pam/PamManager.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
import type { Auth } from '@keeper-security/keeperapi'
22
import type { InMemoryStorage } from '../storage/InMemoryStorage'
3+
import { ConfigManager } from './config/ConfigManager'
34
import { GatewayManager } from './gateway/GatewayManager'
5+
import type {
6+
FormatPamConfigurationsTableOptions,
7+
FormattedPamConfigurationsTable,
8+
ListPamConfigurationsOptions,
9+
ListPamConfigurationsResult,
10+
RenderPamConfigurationsAsciiTableOptions,
11+
CreatePamConfigurationInput,
12+
CreatePamConfigurationResult,
13+
EditPamConfigurationInput,
14+
EditPamConfigurationResult,
15+
RemovePamConfigurationInput,
16+
RemovePamConfigurationResult,
17+
} from './config/configTypes'
418
import type {
519
CreateGatewayInput,
620
CreateGatewayResult,
@@ -21,15 +35,21 @@ export type AuthProvider = () => Auth
2135

2236
export class PamManager {
2337
private readonly gatewayManager: GatewayManager
38+
private readonly configManager: ConfigManager
2439

2540
constructor(storage: InMemoryStorage, authProvider: AuthProvider) {
2641
this.gatewayManager = new GatewayManager(storage, authProvider)
42+
this.configManager = new ConfigManager(storage, authProvider)
2743
}
2844

2945
public getGatewayManager(): GatewayManager {
3046
return this.gatewayManager
3147
}
3248

49+
public getConfigManager(): ConfigManager {
50+
return this.configManager
51+
}
52+
3353
public async listGateways(options: ListGatewaysOptions = {}): Promise<ListGatewaysResult> {
3454
return this.gatewayManager.listGateways(options)
3555
}
@@ -71,4 +91,48 @@ export class PamManager {
7191
public formatGatewaysOutput(result: ListGatewaysResult, options: ListGatewaysOptions = {}): string {
7292
return this.gatewayManager.formatGatewaysOutput(result, options)
7393
}
94+
95+
public listPamConfigurations(options: ListPamConfigurationsOptions = {}): ListPamConfigurationsResult {
96+
return this.configManager.listPamConfigurations(options)
97+
}
98+
99+
public async createPamConfiguration(input: CreatePamConfigurationInput): Promise<CreatePamConfigurationResult> {
100+
return this.configManager.createPamConfiguration(input)
101+
}
102+
103+
public async editPamConfiguration(input: EditPamConfigurationInput): Promise<EditPamConfigurationResult> {
104+
return this.configManager.editPamConfiguration(input)
105+
}
106+
107+
public async removePamConfiguration(input: RemovePamConfigurationInput): Promise<RemovePamConfigurationResult> {
108+
return this.configManager.removePamConfiguration(input)
109+
}
110+
111+
public formatPamConfigurationsTable(
112+
result: ListPamConfigurationsResult,
113+
options: FormatPamConfigurationsTableOptions = {}
114+
): FormattedPamConfigurationsTable {
115+
return this.configManager.formatPamConfigurationsTable(result, options)
116+
}
117+
118+
public renderPamConfigurationsAsciiTable(
119+
table: FormattedPamConfigurationsTable,
120+
options: RenderPamConfigurationsAsciiTableOptions = {}
121+
): string {
122+
return this.configManager.renderPamConfigurationsAsciiTable(table, options)
123+
}
124+
125+
public formatPamConfigurationsJson(
126+
result: ListPamConfigurationsResult,
127+
options: ListPamConfigurationsOptions = {}
128+
): string {
129+
return this.configManager.formatPamConfigurationsJson(result, options)
130+
}
131+
132+
public formatPamConfigurationsOutput(
133+
result: ListPamConfigurationsResult,
134+
options: ListPamConfigurationsOptions = {}
135+
): string {
136+
return this.configManager.formatPamConfigurationsOutput(result, options)
137+
}
74138
}

0 commit comments

Comments
 (0)