Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release JavaScript SDK v16.6.3 #616

Merged
merged 6 commits into from
Sep 18, 2024
Merged
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
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
Loading