Skip to content

Commit d203b87

Browse files
authored
Added support for Enterprise role and node commands
1 parent 725b25d commit d203b87

5 files changed

Lines changed: 174 additions & 15 deletions

File tree

keeperapi/src/browser/platform.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ export const browserPlatform: Platform = class {
9696
if (storage.saveObject) {
9797
await storage.saveObject(this.getStorageKeyId(keyId, 'cbc'), cbcKey)
9898
await storage.saveObject(this.getStorageKeyId(keyId, 'gcm'), gcmKey)
99-
} else {
99+
}
100+
if (extractable && storage.saveKeyBytes) {
100101
await storage.saveKeyBytes(keyId, key)
101102
}
102103
}
@@ -106,15 +107,18 @@ export const browserPlatform: Platform = class {
106107
keyId: string,
107108
privateKey: Uint8Array,
108109
publicKey: Uint8Array,
109-
storage?: KeyStorage
110+
storage?: KeyStorage,
111+
canExport?: boolean
110112
): Promise<void> {
111-
const key = await this.importPrivateKeyEC(privateKey, publicKey)
113+
const extractable = !!canExport
114+
const key = await this.importPrivateKeyEC(privateKey, publicKey, extractable)
112115
cryptoKeysCache['ecc'][keyId] = key
113116

114117
if (storage) {
115118
if (storage.saveObject) {
116119
await storage.saveObject(this.getStorageKeyId(keyId, 'ecc'), key)
117-
} else {
120+
}
121+
if (extractable && storage.saveKeyBytes) {
118122
const jwk = await crypto.subtle.exportKey('jwk', key)
119123
const keyBytes = this.stringToBytes(JSON.stringify(jwk))
120124
await storage.saveKeyBytes(keyId, keyBytes)
@@ -168,10 +172,9 @@ export const browserPlatform: Platform = class {
168172
if (storage?.getObject) {
169173
const storageKeyId = this.getStorageKeyId(keyId, keyType)
170174
const storedKey = await storage.getObject<CryptoKey>(storageKeyId)
171-
if (!storedKey) {
172-
throw new Error('Unable to load crypto key ' + keyId)
175+
if (storedKey) {
176+
return storedKey
173177
}
174-
return storedKey
175178
}
176179

177180
const keyBytes = await this.loadKeyBytes(keyId, storage)
@@ -298,7 +301,7 @@ export const browserPlatform: Platform = class {
298301
break
299302
// TODO: add something like this, need to find pub/priv key pair
300303
case 'ecc':
301-
if (cryptoKeysCache['gcm'][keyId]) {
304+
if (cryptoKeysCache['ecc'][keyId]) {
302305
return
303306
}
304307

@@ -394,7 +397,8 @@ export const browserPlatform: Platform = class {
394397
if (storage.saveObject) {
395398
await storage.saveObject(this.getStorageKeyId(keyId, 'cbc'), cbcKey)
396399
await storage.saveObject(this.getStorageKeyId(keyId, 'gcm'), gcmKey)
397-
} else {
400+
}
401+
if (canExtract && storage.saveKeyBytes) {
398402
const keyBuffer = await crypto.subtle.exportKey('raw', gcmKey)
399403
await storage.saveKeyBytes(keyId, new Uint8Array(keyBuffer))
400404
}
@@ -590,26 +594,32 @@ export const browserPlatform: Platform = class {
590594
return this.privateDecryptECWebCrypto(data, privateKeyImport, id, useHKDF)
591595
}
592596

593-
static async importPrivateKeyEC(privateKey: Uint8Array, publicKey: Uint8Array) {
597+
static async importPrivateKeyEC(privateKey: Uint8Array, publicKey: Uint8Array, extractable = true) {
594598
const x = webSafe64FromBytes(publicKey.subarray(1, 33))
595599
const y = webSafe64FromBytes(publicKey.subarray(33, 65))
596600
const d = webSafe64FromBytes(privateKey)
597601

598602
const jwk = {
599603
crv: 'P-256',
600604
d,
601-
ext: true,
605+
ext: extractable,
602606
key_ops: ['deriveBits'],
603607
kty: 'EC',
604608
x,
605609
y,
606610
}
607611

608-
return this.importECCJsonWebKey(jwk)
612+
return this.importECCJsonWebKey(jwk, extractable)
609613
}
610614

611-
static async importECCJsonWebKey(jwk: JsonWebKey): Promise<CryptoKey> {
612-
return await crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveBits'])
615+
static async importECCJsonWebKey(jwk: JsonWebKey, extractable = true): Promise<CryptoKey> {
616+
return await crypto.subtle.importKey(
617+
'jwk',
618+
jwk,
619+
{ name: 'ECDH', namedCurve: 'P-256' },
620+
extractable,
621+
['deriveBits']
622+
)
613623
}
614624

615625
static async ecdhComputeSharedSecret(

keeperapi/src/commands.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,27 @@ export const enterpriseAllocateIdsCommand = (
211211
): RestCommand<EnterpriseAllocateIdsRequest, KeeperResponse & { base_id: number; number_allocated: number }> =>
212212
createCommand(request, 'enterprise_allocate_ids')
213213

214+
export type NodeEditRequest = {
215+
node_id: number
216+
parent_id: number
217+
encrypted_data: string
218+
license_id?: number
219+
restrict_visibility?: number
220+
}
221+
222+
export const nodeAddCommand = (request: NodeEditRequest): RestCommand<NodeEditRequest, KeeperResponse> =>
223+
createCommand(request, 'node_add')
224+
225+
export const nodeUpdateCommand = (request: NodeEditRequest): RestCommand<NodeEditRequest, KeeperResponse> =>
226+
createCommand(request, 'node_update')
227+
228+
export type NodeDeleteRequest = {
229+
node_id: number
230+
}
231+
232+
export const nodeDeleteCommand = (request: NodeDeleteRequest): RestCommand<NodeDeleteRequest, KeeperResponse> =>
233+
createCommand(request, 'node_delete')
234+
214235
export type RoleEditRequest = {
215236
role_id: number
216237
node_id: number
@@ -232,6 +253,114 @@ export type RoleDeleteRequest = {
232253
export const roleDeleteCommand = (request: RoleDeleteRequest): RestCommand<RoleDeleteRequest, KeeperResponse> =>
233254
createCommand(request, 'role_delete')
234255

256+
export type RoleUserAddRequest = {
257+
role_id: number
258+
enterprise_user_id: number
259+
tree_key?: string
260+
tree_key_type?: string | number
261+
role_admin_key?: string
262+
role_admin_key_type?: string | number
263+
}
264+
265+
export const roleUserAddCommand = (request: RoleUserAddRequest): RestCommand<RoleUserAddRequest, KeeperResponse> =>
266+
createCommand(request, 'role_user_add')
267+
268+
export type RoleUserRemoveRequest = {
269+
role_id: number
270+
enterprise_user_id: number
271+
}
272+
273+
export const roleUserRemoveCommand = (
274+
request: RoleUserRemoveRequest
275+
): RestCommand<RoleUserRemoveRequest, KeeperResponse> => createCommand(request, 'role_user_remove')
276+
277+
export type RoleManagedNodeTreeKey = {
278+
enterprise_user_id: number
279+
tree_key: string
280+
tree_key_type?: string | number
281+
}
282+
283+
export type RoleManagedNodeAddResponse = KeeperResponse & {
284+
missing_tree_keys?: Record<string, string>
285+
missing_ecc_tree_keys?: Record<string, string>
286+
}
287+
288+
export type RoleManagedNodeAddRequest = {
289+
role_id: number
290+
managed_node_id: number
291+
cascade_node_management: boolean
292+
tree_keys?: RoleManagedNodeTreeKey[]
293+
}
294+
295+
export const roleManagedNodeAddCommand = (
296+
request: RoleManagedNodeAddRequest
297+
): RestCommand<RoleManagedNodeAddRequest, RoleManagedNodeAddResponse> => createCommand(request, 'role_managed_node_add')
298+
299+
export type RoleManagedNodeUpdateRequest = {
300+
role_id: number
301+
managed_node_id: number
302+
cascade_node_management?: boolean
303+
}
304+
305+
export const roleManagedNodeUpdateCommand = (
306+
request: RoleManagedNodeUpdateRequest
307+
): RestCommand<RoleManagedNodeUpdateRequest, KeeperResponse> => createCommand(request, 'role_managed_node_update')
308+
309+
export type RoleManagedNodeRemoveRequest = {
310+
role_id: number
311+
managed_node_id: number
312+
}
313+
314+
export const roleManagedNodeRemoveCommand = (
315+
request: RoleManagedNodeRemoveRequest
316+
): RestCommand<RoleManagedNodeRemoveRequest, KeeperResponse> => createCommand(request, 'role_managed_node_remove')
317+
318+
export type ManagedNodeRoleKey = {
319+
enterprise_user_id: number
320+
role_key: string
321+
tree_key_type?: string | number
322+
}
323+
324+
export type ManagedNodeMspKey = {
325+
mc_enterprise_id: number
326+
tree_key: string
327+
}
328+
329+
export type ManagedNodePrivilegeAddRequest = {
330+
role_id: number
331+
managed_node_id: number
332+
privilege: string
333+
role_key_enc_with_tree_key?: string
334+
role_public_key?: string
335+
role_private_key?: string
336+
role_keys?: ManagedNodeRoleKey[]
337+
msp_keys?: ManagedNodeMspKey[]
338+
}
339+
340+
export type ManagedNodePrivilegeAddResponse = KeeperResponse & {
341+
status?: {
342+
missing_keys?: Record<string, string>
343+
invalid_users?: number[]
344+
cant_be_pending?: number[]
345+
}
346+
}
347+
348+
export const managedNodePrivilegeAddCommand = (
349+
request: ManagedNodePrivilegeAddRequest
350+
): RestCommand<ManagedNodePrivilegeAddRequest, ManagedNodePrivilegeAddResponse> =>
351+
createCommand(request, 'managed_node_privilege_add')
352+
353+
export type ManagedNodePrivilegeRemoveRequest = {
354+
role_id: number
355+
managed_node_id: number
356+
privilege: string
357+
}
358+
359+
export const managedNodePrivilegeRemoveCommand = (
360+
request: ManagedNodePrivilegeRemoveRequest
361+
): RestCommand<ManagedNodePrivilegeRemoveRequest, KeeperResponse> =>
362+
createCommand(request, 'managed_node_privilege_remove')
363+
235364
export type MoveRequest = {
236365
to_type: 'user_folder' | 'shared_folder' | 'shared_folder_folder'
237366
to_uid?: string
@@ -379,6 +508,16 @@ export const teamEnterpriseUserRemoveCommand = (
379508
request: TeamUserCommandRequest
380509
): RestCommand<TeamUserCommandRequest, KeeperResponse> => createCommand(request, 'team_enterprise_user_remove')
381510

511+
export type TeamEnterpriseUserUpdateRequest = {
512+
team_uid: string
513+
enterprise_user_id: number
514+
user_type: number
515+
}
516+
517+
export const teamEnterpriseUserUpdateCommand = (
518+
request: TeamEnterpriseUserUpdateRequest
519+
): RestCommand<TeamEnterpriseUserUpdateRequest, KeeperResponse> => createCommand(request, 'team_enterprise_user_update')
520+
382521
export type TeamGetKeysRequest = {
383522
teams: string[]
384523
}

keeperapi/src/node/platform.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ export const nodePlatform: Platform = class {
6565
keyId: string,
6666
privateKey: Uint8Array,
6767
_publicKey: Uint8Array,
68-
storage?: KeyStorage
68+
storage?: KeyStorage,
69+
_canExport?: boolean
6970
): Promise<void> {
7071
this.importKey(keyId, privateKey, storage)
7172
}

keeperapi/src/restMessages.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,11 @@ export const enterpriseUsersLockMessage = (
640640
): RestMessage<Enterprise.ILockUsersRequest, Enterprise.ILockUsersResponse> =>
641641
createMessage(data, 'enterprise/enterprise_users_lock', Enterprise.LockUsersRequest, Enterprise.LockUsersResponse)
642642

643+
export const disableTwoFaMessage = (
644+
data: Enterprise.IEnterpriseUserIds
645+
): RestInMessage<Enterprise.IEnterpriseUserIds> =>
646+
createInMessage(data, 'enterprise/disable_two_fa', Enterprise.EnterpriseUserIds)
647+
643648
export const setV2AlternatePasswordMessage = (
644649
data: Authentication.IUserAuthRequest
645650
): RestInMessage<Authentication.IUserAuthRequest> =>

keeperapi/src/syncDown/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export const mapTeamKeyType = (keyType: Folder.EncryptedKeyType, teamUid: string
1414
keyId = teamUid
1515
encryptionType = 'cbc'
1616
break
17+
case Folder.EncryptedKeyType.encrypted_by_data_key_gcm:
18+
keyId = teamUid
19+
encryptionType = 'gcm'
20+
break
1721
case Folder.EncryptedKeyType.encrypted_by_public_key:
1822
keyId = `${teamUid}_priv`
1923
encryptionType = 'rsa'

0 commit comments

Comments
 (0)