Skip to content

Commit

Permalink
Release JavaScript SDK v16.6.3 (#616)
Browse files Browse the repository at this point in the history
* KSM-521 dependencies upgrade (#615)

* KSM-521 - Updated package dependencies

* KSM-489 - JavaScript SDK: Added transaction support (#562)

* KSM-489 - Added transaction support

* KSM-549 - Stop generating UIDs that start with "-" (#645)

* KSM-556 - Added new and updated PAM field types (#651)

* Bump JS SDK version to 16.6.3
  • Loading branch information
idimov-keeper authored Sep 18, 2024
1 parent 1d13302 commit 0e0896e
Show file tree
Hide file tree
Showing 7 changed files with 1,881 additions and 7,620 deletions.
8 changes: 7 additions & 1 deletion sdk/javascript/packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
For more information see our official documentation page https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/javascript-sdk

# Change Log
## 16.6.3
- KSM-489 - Added transaction support for updateSecret
- KSM-521 - Dependencies upgrade
- KSM-549 - Stop generating UIDs that start with "-"
- KSM-556 - Added new field types and updated PAM field types

## 16.6.2
- KSM-487 - Dependencies upgrade

Expand Down Expand Up @@ -35,4 +41,4 @@ For more information see our official documentation page https://docs.keeper.io/
## 16.3.3

- KSM-273 - Avoid reliance on external package for file upload with Node
- Added support to Japan `JP` and Canada `CA` regions
- Added support to Japan `JP` and Canada `CA` regions
9,232 changes: 1,645 additions & 7,587 deletions sdk/javascript/packages/core/package-lock.json

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions sdk/javascript/packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@keeper-security/secrets-manager-core",
"version": "16.6.2",
"version": "16.6.3",
"description": "Keeper Secrets Manager Javascript SDK",
"browser": "dist/index.es.js",
"main": "dist/index.cjs.js",
Expand All @@ -16,19 +16,19 @@
"publish-to-npm": "npm publish"
},
"devDependencies": {
"@babel/core": "^7.17.12",
"@babel/preset-env": "^7.15.6",
"@babel/preset-typescript": "^7.15.0",
"@types/jest": "^27.5.2",
"@types/node": "^17.0.45",
"babel-jest": "^27.5.1",
"jest": "^27.5.1",
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.4",
"@babel/preset-typescript": "^7.24.7",
"@types/jest": "^29.5.12",
"@types/node": "^22.5.4",
"babel-jest": "^29.7.0",
"jest": "^29.7.0",
"rollup": "^2.79.1",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.34.1",
"rollup-plugin-typescript2": "^0.35.0",
"rollup-plugin-version-injector": "^1.3.3",
"ts-jest": "^27.1.5",
"ts-node": "^10.7.0",
"typescript": "^4.6.4"
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
210 changes: 203 additions & 7 deletions sdk/javascript/packages/core/src/keeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,17 @@ export type CreateOptions = {
subFolderUid?: string
}

export enum UpdateTransactionType {
General = "general",
Rotation = "rotation"
}

type AnyPayload =
GetPayload
| DeletePayload
| DeleteFolderPayload
| UpdatePayload
| CompleteTransactionPayload
| CreatePayload
| CreateFolderPayload
| UpdateFolderPayload
Expand Down Expand Up @@ -89,6 +95,11 @@ type UpdatePayload = CommonPayload & {
recordUid: string
data: string
revision: number
transactionType?: UpdateTransactionType
}

type CompleteTransactionPayload = CommonPayload & {
recordUid: string
}

type CreatePayload = CommonPayload & {
Expand Down Expand Up @@ -228,6 +239,19 @@ type KeeperError = {
key_id?: number
}

const getUidBytes = (): Uint8Array => {
const dash = new Uint8Array([0b1111_1000, 0b0111_1111])
let bytes = new Uint8Array(16)
for (let i = 0; i < 8; i++) {
bytes = platform.getRandomBytes(16)
if ((dash[0] & bytes[0]) != dash[0]) break
}
if ((dash[0] & bytes[0]) == dash[0])
bytes[0] = bytes[0] & dash[1]

return bytes
}

const prepareGetPayload = async (storage: KeyValueStorage, queryOptions?: QueryOptions): Promise<GetPayload> => {
const clientId = await storage.getString(KEY_CLIENT_ID)
if (!clientId) {
Expand All @@ -251,20 +275,37 @@ const prepareGetPayload = async (storage: KeyValueStorage, queryOptions?: QueryO
return payload
}

const prepareUpdatePayload = async (storage: KeyValueStorage, record: KeeperRecord): Promise<UpdatePayload> => {
const prepareUpdatePayload = async (storage: KeyValueStorage, record: KeeperRecord, transactionType?: UpdateTransactionType): Promise<UpdatePayload> => {
const clientId = await storage.getString(KEY_CLIENT_ID)
if (!clientId) {
throw new Error('Client Id is missing from the configuration')
}
const recordBytes = platform.stringToBytes(JSON.stringify(record.data))
const encryptedRecord = await platform.encrypt(recordBytes, record.recordUid)
return {
const payload: UpdatePayload = {
clientVersion: 'ms' + packageVersion,
clientId: clientId,
recordUid: record.recordUid,
data: webSafe64FromBytes(encryptedRecord),
revision: record.revision
}
if (transactionType) {
payload.transactionType = transactionType
}
return payload
}

const prepareCompleteTransactionPayload = async (storage: KeyValueStorage, recordUid: string): Promise<CompleteTransactionPayload> => {
const clientId = await storage.getString(KEY_CLIENT_ID)
if (!clientId) {
throw new Error('Client Id is missing from the configuration')
}
const payload: CompleteTransactionPayload = {
clientVersion: 'ms' + packageVersion,
clientId: clientId,
recordUid: recordUid,
}
return payload
}

const prepareDeletePayload = async (storage: KeyValueStorage, recordUids: string[]): Promise<DeletePayload> => {
Expand Down Expand Up @@ -303,7 +344,7 @@ const prepareCreatePayload = async (storage: KeyValueStorage, createOptions: Cre
}
const recordBytes = platform.stringToBytes(JSON.stringify(recordData))
const recordKey = platform.getRandomBytes(32)
const recordUid = platform.getRandomBytes(16)
const recordUid = getUidBytes()
const encryptedRecord = await platform.encryptWithKey(recordBytes, recordKey)
const encryptedRecordKey = await platform.publicEncrypt(recordKey, ownerPublicKey)
const encryptedFolderKey = await platform.encrypt(recordKey, createOptions.folderUid)
Expand All @@ -328,7 +369,7 @@ const prepareCreateFolderPayload = async (storage: KeyValueStorage, createOption
name: folderName
}))
const folderKey = platform.getRandomBytes(32)
const folderUid = platform.getRandomBytes(16)
const folderUid = getUidBytes()
const encryptedFolderData = await platform.encryptWithKey(folderDataBytes, folderKey, true)
const encryptedFolderKey = await platform.encrypt(folderKey, createOptions.folderUid, undefined, true)
return {
Expand Down Expand Up @@ -867,11 +908,17 @@ export const getSecretByTitle = async (options: SecretManagerOptions, recordTitl
return secrets.records.find(record => record.data.title === recordTitle)
}

export const updateSecret = async (options: SecretManagerOptions, record: KeeperRecord): Promise<void> => {
const payload = await prepareUpdatePayload(options.storage, record)
export const updateSecret = async (options: SecretManagerOptions, record: KeeperRecord, transactionType?: UpdateTransactionType): Promise<void> => {
const payload = await prepareUpdatePayload(options.storage, record, transactionType)
await postQuery(options, 'update_secret', payload)
}

export const completeTransaction = async (options: SecretManagerOptions, recordUid: string, rollback: boolean = false): Promise<void> => {
const payload = await prepareCompleteTransactionPayload(options.storage, recordUid)
const route = (rollback ? "rollback_secret_update" : "finalize_secret_update")
await postQuery(options, route, payload)
}

export const deleteSecret = async (options: SecretManagerOptions, recordUids: string[]): Promise<SecretsManagerDeleteResponse> => {
const payload = await prepareDeletePayload(options.storage, recordUids)
const responseData = await postQuery(options, 'delete_secret', payload)
Expand Down Expand Up @@ -994,6 +1041,7 @@ export class UrlField extends KeeperRecordField {
}
}

// 'file' - obsolete and removed legacy field - "fldt_file": { key: 'file_or_photo', default: "File or Photo" },
export class FileRefField extends KeeperRecordField {
required? : boolean
value?: string[]
Expand All @@ -1015,6 +1063,17 @@ export class OneTimeCodeField extends KeeperRecordField {
}
}

export class OtpField extends KeeperRecordField {
required? : boolean
privacyScreen? : boolean
value?: string[]
constructor(value: string) {
super()
this.type = 'otp'
this.value = [value]
}
}

export type Name = {
first?: string
middle?: string
Expand Down Expand Up @@ -1308,7 +1367,10 @@ export class RecordRefField extends KeeperRecordField {

export type Schedule = {
type?: string
utcTime?: string
cron?: string
// utcTime - replaced by time and tz
time?: string
tz?: string
weekday?: string
intervalCount?: number
}
Expand Down Expand Up @@ -1371,10 +1433,19 @@ export class PamHostnameField extends KeeperRecordField {
}
}

export type AllowedSettings = {
connections? : boolean
portForwards? : boolean
rotation? : boolean
sessionRecording? : boolean
typescriptRecording? : boolean
}

export type PamResource = {
controllerUid?: string
folderUid?: string
resourceRef?: string[]
allowedSettings?: AllowedSettings
}

export class PamResourceField extends KeeperRecordField {
Expand Down Expand Up @@ -1426,3 +1497,128 @@ export class PasskeyField extends KeeperRecordField {
this.value = [value]
}
}

export class IsSSIDHiddenField extends KeeperRecordField {
required? : boolean
value?: boolean[]
constructor(value: boolean) {
super()
this.type = 'isSSIDHidden'
this.value = [value]
}
}

export class WifiEncryptionField extends KeeperRecordField {
required? : boolean
value?: string[]
constructor(value: string) {
super()
this.type = 'wifiEncryption'
this.value = [value]
}
}

export class DropdownField extends KeeperRecordField {
required? : boolean
value?: string[]
constructor(value: string) {
super()
this.type = 'dropdown'
this.value = [value]
}
}

export class RbiUrlField extends KeeperRecordField {
required? : boolean
value?: string[]
constructor(value: string) {
super()
this.type = 'rbiUrl'
this.value = [value]
}
}

export type AppFiller = {
applicationTitle?: string
contentFilter?: string
macroSequence?: string
}

export class AppFillerField extends KeeperRecordField {
required?: boolean
privacyScreen? : boolean
value?: AppFiller[]
constructor(value: AppFiller) {
super()
this.type = 'appFiller'
this.value = [value]
}
}

export type PamRbiConnection = {
protocol?: string
userRecords?: string[]
allowUrlManipulation?: boolean
allowedUrlPatterns?: string
allowedResourceUrlPatterns?: string
httpCredentialsUid?: string
autofillConfiguration?: string
}

export type PamRemoteBrowserSetting = {
connection?: PamRbiConnection
}

export class PamRemoteBrowserSettingsField extends KeeperRecordField {
required?: boolean
value?: PamRemoteBrowserSetting[]
constructor(value: PamRemoteBrowserSetting) {
super()
this.type = 'pamRemoteBrowserSettings'
this.value = [value]
}
}

export type PamSettingsConnection = {
protocol?: string
userRecords?: string[]
security?: string
ignoreCert?: boolean
resizeMethod?: string
colorScheme?: string
}

export type PamSettingsPortForward = {
reusePort?: boolean
port?: string
}

export type PamSetting = {
portForward?: PamSettingsPortForward[]
connection?: PamSettingsConnection[]
}

export class PamSettingsField extends KeeperRecordField {
required?: boolean
value?: PamSetting[]
constructor(value: PamSetting) {
super()
this.type = 'pamSettings'
this.value = [value]
}
}

export class TrafficEncryptionSeedField extends KeeperRecordField {
required? : boolean
value?: string[]
constructor(value: string) {
super()
this.type = 'trafficEncryptionSeed'
this.value = [value]
}
}

// List of retired field types:
// trafficEncryptionKey - replaced by trafficEncryptionSeed
// pamProvider - deprecated for legacy/internal use only
// controller - deprecated for legacy/internal use only
Loading

0 comments on commit 0e0896e

Please sign in to comment.