Skip to content

Commit 980ba9c

Browse files
committed
Improve based on PR comments
1 parent 3370a09 commit 980ba9c

11 files changed

Lines changed: 96 additions & 64 deletions

KeeperSdk/src/pam/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ export {
221221
resolveGatewayName,
222222
} from './rotation'
223223
export type {
224-
AuthProvider as RotationAuthProvider,
225224
RotationListFormatInput,
226225
ListRotationSchedulesOptions,
227226
RotationListRow,

KeeperSdk/src/pam/rotation/RotationManager.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Auth } from '@keeper-security/keeperapi'
22
import type { InMemoryStorage } from '../../storage/InMemoryStorage'
3+
import type { AuthProvider } from '../PamManager'
34
import { KeeperSdkError, ResultCodes } from '../../utils'
45
import { formatRotationInfoJson, formatRotationInfoOutput, getRotationInfo } from './getRotationInfo'
56
import {
@@ -36,8 +37,6 @@ import type {
3637
DeleteRotationScriptResult,
3738
} from './rotationScriptTypes'
3839

39-
export type AuthProvider = () => Auth
40-
4140
export class RotationManager {
4241
private readonly storage: InMemoryStorage
4342
private readonly authProvider: AuthProvider

KeeperSdk/src/pam/rotation/addRotationScript.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { Auth } from '@keeper-security/keeperapi'
2-
import type { DRecord } from '@keeper-security/keeperapi'
1+
import * as path from 'path'
2+
import type { Auth, DRecord } from '@keeper-security/keeperapi'
33
import { generateUid } from '@keeper-security/keeperapi'
44
import type { InMemoryStorage } from '../../storage/InMemoryStorage'
5-
import { getRecordTitle, getRecordType } from '../../records/RecordUtils'
5+
import { VaultObjectKind } from '../../folders/folderHelpers'
6+
import { getRecordType } from '../../records/RecordUtils'
67
import type { AddRotationScriptInput, AddRotationScriptResult, RotationScriptValue } from './rotationScriptTypes'
78
import { KeeperSdkError, ResultCodes, extractErrorMessage } from '../../utils'
89
import {
@@ -12,7 +13,6 @@ import {
1213
updatePamRecordFields,
1314
} from './rotationScriptHelpers'
1415
import { SCRIPT_FIELD_TYPE, SCRIPT_FIELD_LABEL } from './rotationConstants'
15-
import type { PamRecordData } from './rotationScriptTypes'
1616

1717
export async function addRotationScript(
1818
auth: Auth,
@@ -32,11 +32,8 @@ export async function addRotationScript(
3232
const recordType = getRecordType(record)
3333
const currentRevision = record.revision || 0
3434

35-
const recordData = (record.data as PamRecordData) || { fields: [] }
36-
const dataFields = recordData.fields || []
37-
38-
const fs = require('fs')
39-
const path = require('path')
35+
const recordData = record.data
36+
const dataFields = recordData.fields
4037
const fileName = path.basename(expandedPath)
4138

4239
const fileUid = generateUid()
@@ -48,7 +45,7 @@ export async function addRotationScript(
4845

4946
if (Array.isArray(input.credentialUids)) {
5047
for (const credUid of input.credentialUids) {
51-
const credRecord = storage.getByUid<DRecord>(1 as any, credUid)
48+
const credRecord = storage.getByUid<DRecord>(VaultObjectKind.Record, credUid)
5249
if (!credRecord) {
5350
warnings.push(`Credential record not found: ${credUid}`)
5451
continue
@@ -65,7 +62,7 @@ export async function addRotationScript(
6562

6663
dataFields.push(newScriptField)
6764
recordData.fields = dataFields
68-
;(record as any).data = recordData
65+
record.data = recordData
6966

7067
await updatePamRecordFields(auth, record, recordType, dataFields, currentRevision, storage)
7168

KeeperSdk/src/pam/rotation/deleteRotationScript.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Auth } from '@keeper-security/keeperapi'
2-
import type { DRecord } from '@keeper-security/keeperapi'
32
import type { InMemoryStorage } from '../../storage/InMemoryStorage'
43
import { getRecordType } from '../../records/RecordUtils'
54
import type { DeleteRotationScriptInput, DeleteRotationScriptResult } from './rotationScriptTypes'
@@ -11,7 +10,6 @@ import {
1110
findScriptByUidOrName,
1211
updatePamRecordFields,
1312
} from './rotationScriptHelpers'
14-
import type { PamRecordData } from './rotationScriptTypes'
1513

1614
/**
1715
* Delete a rotation script from a PAM record
@@ -28,8 +26,8 @@ export async function deleteRotationScript(
2826
const recordType = getRecordType(record)
2927
const currentRevision = record.revision || 0
3028

31-
const recordData = (record.data as PamRecordData) || { fields: [] }
32-
const dataFields = recordData.fields || []
29+
const recordData = record.data
30+
const dataFields = recordData.fields
3331

3432
const scriptFields = findScriptFieldsInRecord(recordData)
3533
if (scriptFields.length === 0) {
@@ -54,15 +52,18 @@ export async function deleteRotationScript(
5452
}
5553

5654
const field = dataFields[targetScript.fieldIndex]
57-
const scriptArray = field.value as any[]
55+
if (!field || field.type !== 'script' || !Array.isArray(field.value)) {
56+
throw new KeeperSdkError('Rotation script field is invalid', ResultCodes.PAM_CONFIG_INVALID)
57+
}
58+
const scriptArray = field.value
5859
scriptArray.splice(targetScript.scriptIndex, 1)
5960

6061
if (scriptArray.length === 0) {
6162
dataFields.splice(targetScript.fieldIndex, 1)
6263
}
6364

6465
recordData.fields = dataFields
65-
;(record as any).data = recordData
66+
record.data = recordData
6667

6768
await updatePamRecordFields(auth, record, recordType, dataFields, currentRevision, storage)
6869

KeeperSdk/src/pam/rotation/editRotation.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
ScheduleData,
1212
} from './rotationTypes'
1313
import { getVaultRecord, recordExistsInVault, getVaultRecordTitleType } from './rotationHelpers'
14-
import { RECORD_ROTATION_KIND } from './rotationConstants'
14+
import { MANUAL_ROTATION_LABEL, RECORD_ROTATION_KIND } from './rotationConstants'
1515

1616
const DEFAULT_PAM_SPECIAL_CHAR = '!@#$%^&*()_+-=[]{}|;:,.<>?'
1717

@@ -125,7 +125,7 @@ export async function editRotation(
125125
const reencrypted = await encryptPasswordComplexity(
126126
storage,
127127
recordUid,
128-
currentRotation.pwdComplexity as any
128+
currentRotation.pwdComplexity
129129
)
130130
if (reencrypted) {
131131
currentComplexity = platform.base64ToBytes(reencrypted)
@@ -173,7 +173,7 @@ export async function editRotation(
173173
finalResourceUidBytes = normal64Bytes(input.resourceUid)
174174
}
175175

176-
let schedule = finalScheduleData ? formatScheduleType(finalScheduleData) : 'On-Demand'
176+
let schedule = finalScheduleData ? formatScheduleType(finalScheduleData) : MANUAL_ROTATION_LABEL
177177
let complexity = input.passwordComplexity ? formatComplexity(input.passwordComplexity) : ''
178178

179179
const configUidBytes = configUid ? normal64Bytes(configUid) : new Uint8Array()
@@ -248,9 +248,9 @@ function validateAndBuildScheduleData(input: EditRotationInput): ScheduleData[]
248248

249249
function formatScheduleType(scheduleData: ScheduleData[] | null): string {
250250
if (!scheduleData || scheduleData.length === 0) {
251-
return 'On-Demand'
251+
return MANUAL_ROTATION_LABEL
252252
}
253-
return (scheduleData[0] as any).type || 'Scheduled'
253+
return scheduleData[0].type || 'Scheduled'
254254
}
255255

256256
function formatComplexity(complexity: PasswordComplexityInput): string {

KeeperSdk/src/pam/rotation/editRotationScript.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
findScriptByUidOrName,
1212
updatePamRecordFields,
1313
} from './rotationScriptHelpers'
14-
import type { PamRecordData } from './rotationScriptTypes'
1514

1615
export async function editRotationScript(
1716
auth: Auth,
@@ -30,8 +29,8 @@ export async function editRotationScript(
3029
const recordType = getRecordType(record)
3130
const currentRevision = record.revision || 0
3231

33-
const recordData = (record.data as PamRecordData) || { fields: [] }
34-
const dataFields = recordData.fields || []
32+
const recordData = record.data
33+
const dataFields = recordData.fields
3534

3635
const found = findScriptByUidOrName(storage, recordData, scriptName)
3736
if (!found) {
@@ -84,7 +83,7 @@ export async function editRotationScript(
8483
}
8584

8685
recordData.fields = dataFields
87-
;(record as any).data = recordData
86+
record.data = recordData
8887

8988
await updatePamRecordFields(auth, record, recordType, dataFields, currentRevision, storage)
9089

KeeperSdk/src/pam/rotation/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export { RotationManager } from './RotationManager'
2-
export type { AuthProvider } from './RotationManager'
32

43
export {
54
listRotationSchedules,
@@ -44,6 +43,10 @@ export type {
4443

4544
export type {
4645
RotationScriptValue,
46+
PamRecord,
47+
PamRecordData,
48+
RecordField,
49+
ScriptField,
4750
RotationScript,
4851
ListRotationScriptsResult,
4952
AddRotationScriptInput,

KeeperSdk/src/pam/rotation/listRotationScripts.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import type { InMemoryStorage } from '../../storage/InMemoryStorage'
44
import { VaultObjectKind } from '../../folders/folderHelpers'
55
import { getRecordTitle, getRecordType } from '../../records/RecordUtils'
66
import type { RotationScript, ListRotationScriptsResult, ListRotationScriptsOptions } from './rotationScriptTypes'
7-
import { findScriptFieldsInRecord } from './rotationScriptHelpers'
8-
import type { PamRecordData } from './rotationScriptTypes'
7+
import { findScriptFieldsInRecord, isPamRecord } from './rotationScriptHelpers'
98

109
export async function listRotationScripts(
1110
_auth: Auth,
@@ -34,7 +33,8 @@ export async function listRotationScripts(
3433
}
3534
}
3635

37-
const recordData = (record.data as PamRecordData) || { fields: [] }
36+
if (!isPamRecord(record)) continue
37+
const recordData = record.data
3838
const scriptFields = findScriptFieldsInRecord(recordData)
3939

4040
if (scriptFields.length > 0) {

KeeperSdk/src/pam/rotation/rotationScriptHelpers.ts

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ import { getRecordTitle, getRecordType } from '../../records/RecordUtils'
77
import { updateRecord } from '../../records/RecordOperations'
88
import { KeeperSdkError, ResultCodes } from '../../utils'
99
import { SCRIPT_FIELD_TYPE } from './rotationConstants'
10-
import type { PamRecordData, RotationScriptValue, ScriptFieldLocation, ScriptSearchResult } from './rotationScriptTypes'
11-
12-
export function findPamRecordsByName(storage: InMemoryStorage, searchText: string): DRecord[] {
13-
const results: DRecord[] = []
10+
import type {
11+
PamRecord,
12+
PamRecordData,
13+
RecordField,
14+
RotationScriptValue,
15+
ScriptField,
16+
ScriptFieldLocation,
17+
ScriptSearchResult,
18+
} from './rotationScriptTypes'
19+
20+
export function findPamRecordsByName(storage: InMemoryStorage, searchText: string): PamRecord[] {
21+
const results: PamRecord[] = []
1422
const searchLower = searchText.toLowerCase()
1523

1624
const allRecords = storage.getRecords()
@@ -21,6 +29,7 @@ export function findPamRecordsByName(storage: InMemoryStorage, searchText: strin
2129
if (recordType !== 'pamUser' && recordType !== 'pamDirectory') {
2230
continue
2331
}
32+
if (!isPamRecord(record)) continue
2433

2534
const title = getRecordTitle(record) || ''
2635
if (
@@ -39,7 +48,15 @@ export function getRecordTitleSafe(record: DRecord): string {
3948
return getRecordTitle(record) || record.uid
4049
}
4150

42-
export function getSinglePamRecord(storage: InMemoryStorage, recordName: string): DRecord {
51+
function isPamRecordData(data: unknown): data is PamRecordData {
52+
return typeof data === 'object' && data !== null && Array.isArray((data as { fields?: unknown }).fields)
53+
}
54+
55+
export function isPamRecord(record: DRecord): record is PamRecord {
56+
return isPamRecordData(record.data)
57+
}
58+
59+
export function getSinglePamRecord(storage: InMemoryStorage, recordName: string): PamRecord {
4360
const recordNameTrimmed = recordName?.trim()
4461
if (!recordNameTrimmed) {
4562
throw new KeeperSdkError('Record UID or title is required', ResultCodes.INVALID_PATTERN)
@@ -66,34 +83,45 @@ export function getSinglePamRecord(storage: InMemoryStorage, recordName: string)
6683
)
6784
}
6885

86+
if (!isPamRecord(record)) {
87+
throw new KeeperSdkError(
88+
`PAM record "${recordNameTrimmed}" has invalid record data`,
89+
ResultCodes.PAM_CONFIG_INVALID
90+
)
91+
}
92+
6993
return record
7094
}
7195

96+
function isRotationScriptValue(value: unknown): value is RotationScriptValue {
97+
if (typeof value !== 'object' || value === null) return false
98+
const candidate = value as Partial<RotationScriptValue>
99+
return (
100+
typeof candidate.fileRef === 'string' &&
101+
Array.isArray(candidate.recordRef) &&
102+
candidate.recordRef.every((uid): uid is string => typeof uid === 'string') &&
103+
typeof candidate.command === 'string'
104+
)
105+
}
106+
107+
function isScriptField(field: RecordField): field is ScriptField {
108+
return field.type === SCRIPT_FIELD_TYPE && Array.isArray(field.value) && field.value.every(isRotationScriptValue)
109+
}
110+
72111
export function findScriptFieldsInRecord(recordData: PamRecordData): ScriptFieldLocation[] {
73112
const results: ScriptFieldLocation[] = []
74113

75114
const dataFields = recordData.fields || []
76115
for (let i = 0; i < dataFields.length; i++) {
77116
const field = dataFields[i]
78-
if (field.type !== SCRIPT_FIELD_TYPE) continue
79-
80-
const value = field.value as unknown
81-
if (!Array.isArray(value)) continue
82-
83-
for (let j = 0; j < value.length; j++) {
84-
const script = value[j]
85-
if (
86-
script &&
87-
typeof script === 'object' &&
88-
'fileRef' in script &&
89-
typeof (script as any).fileRef === 'string'
90-
) {
91-
results.push({
92-
fieldIndex: i,
93-
scriptIndex: j,
94-
script: script as RotationScriptValue,
95-
})
96-
}
117+
if (!isScriptField(field)) continue
118+
119+
for (let j = 0; j < field.value.length; j++) {
120+
results.push({
121+
fieldIndex: i,
122+
scriptIndex: j,
123+
script: field.value[j],
124+
})
97125
}
98126
}
99127

@@ -128,22 +156,23 @@ export function findScriptByUidOrName(
128156
}
129157

130158
export function expandFilePath(filePath: string): string {
131-
return filePath.startsWith('~') ? path.join(process.env.HOME || '', filePath.slice(1)) : filePath
159+
const expandedPath = filePath.startsWith('~') ? path.join(process.env.HOME || '', filePath.slice(1)) : filePath
160+
return path.resolve(expandedPath)
132161
}
133162

134163
export function validateScriptFileExists(filePath: string): string {
135164
const expandedPath = expandFilePath(filePath)
136-
if (!fs.existsSync(expandedPath)) {
165+
if (!fs.existsSync(expandedPath) || !fs.statSync(expandedPath).isFile()) {
137166
throw new KeeperSdkError(`Script file not found: ${filePath}`, ResultCodes.PAM_CONFIG_CREATE_FAILED)
138167
}
139168
return expandedPath
140169
}
141170

142171
export async function updatePamRecordFields(
143172
auth: Auth,
144-
record: DRecord,
173+
record: PamRecord,
145174
recordType: string,
146-
fields: unknown[],
175+
fields: RecordField[],
147176
currentRevision: number,
148177
storage: InMemoryStorage
149178
): Promise<void> {
@@ -155,14 +184,14 @@ export async function updatePamRecordFields(
155184
)
156185
}
157186

158-
const recordData = (record.data as PamRecordData) || { fields: [] }
187+
const recordData = record.data
159188
const updateResult = await updateRecord(
160189
auth,
161190
record.uid,
162191
{
163192
type: recordType,
164193
title: getRecordTitle(record) || '',
165-
fields: fields as any,
194+
fields,
166195
notes: recordData.notes || '',
167196
},
168197
currentRevision,

0 commit comments

Comments
 (0)