@keeper-security/keeper-sdk-javascript 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/ConsoleAuthUI.d.ts +10 -0
- package/dist/auth/ConsoleAuthUI.js +152 -0
- package/dist/auth/ConsoleAuthUI.js.map +1 -0
- package/dist/auth/ConsoleLogin.d.ts +8 -0
- package/dist/auth/ConsoleLogin.js +266 -0
- package/dist/auth/ConsoleLogin.js.map +1 -0
- package/dist/auth/SessionManager.d.ts +66 -0
- package/dist/auth/SessionManager.js +211 -0
- package/dist/auth/SessionManager.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/records/RecordOperations.d.ts +79 -0
- package/dist/records/RecordOperations.js +346 -0
- package/dist/records/RecordOperations.js.map +1 -0
- package/dist/records/RecordUtils.d.ts +36 -0
- package/dist/records/RecordUtils.js +224 -0
- package/dist/records/RecordUtils.js.map +1 -0
- package/dist/sharing/Sharing.d.ts +27 -0
- package/dist/sharing/Sharing.js +125 -0
- package/dist/sharing/Sharing.js.map +1 -0
- package/dist/src/auth/ConsoleAuthUI.d.ts +10 -0
- package/dist/src/auth/ConsoleAuthUI.js +161 -0
- package/dist/src/auth/ConsoleAuthUI.js.map +1 -0
- package/dist/src/auth/ConsoleLogin.d.ts +8 -0
- package/dist/src/auth/ConsoleLogin.js +311 -0
- package/dist/src/auth/ConsoleLogin.js.map +1 -0
- package/dist/src/auth/SessionManager.d.ts +67 -0
- package/dist/src/auth/SessionManager.js +212 -0
- package/dist/src/auth/SessionManager.js.map +1 -0
- package/dist/src/folders/FolderManager.d.ts +57 -0
- package/dist/src/folders/FolderManager.js +108 -0
- package/dist/src/folders/FolderManager.js.map +1 -0
- package/dist/src/folders/addFolder.d.ts +32 -0
- package/dist/src/folders/addFolder.js +207 -0
- package/dist/src/folders/addFolder.js.map +1 -0
- package/dist/src/folders/changeDirectory.d.ts +19 -0
- package/dist/src/folders/changeDirectory.js +171 -0
- package/dist/src/folders/changeDirectory.js.map +1 -0
- package/dist/src/folders/deleteFolder.d.ts +17 -0
- package/dist/src/folders/deleteFolder.js +237 -0
- package/dist/src/folders/deleteFolder.js.map +1 -0
- package/dist/src/folders/folderHelpers.d.ts +48 -0
- package/dist/src/folders/folderHelpers.js +100 -0
- package/dist/src/folders/folderHelpers.js.map +1 -0
- package/dist/src/folders/folderTree.d.ts +29 -0
- package/dist/src/folders/folderTree.js +250 -0
- package/dist/src/folders/folderTree.js.map +1 -0
- package/dist/src/folders/getFolder.d.ts +56 -0
- package/dist/src/folders/getFolder.js +143 -0
- package/dist/src/folders/getFolder.js.map +1 -0
- package/dist/src/folders/listFolder.d.ts +48 -0
- package/dist/src/folders/listFolder.js +276 -0
- package/dist/src/folders/listFolder.js.map +1 -0
- package/dist/src/folders/updateFolder.d.ts +31 -0
- package/dist/src/folders/updateFolder.js +137 -0
- package/dist/src/folders/updateFolder.js.map +1 -0
- package/dist/src/index.d.ts +49 -0
- package/dist/src/index.js +151 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/records/RecordOperations.d.ts +80 -0
- package/dist/src/records/RecordOperations.js +356 -0
- package/dist/src/records/RecordOperations.js.map +1 -0
- package/dist/src/records/RecordUtils.d.ts +37 -0
- package/dist/src/records/RecordUtils.js +263 -0
- package/dist/src/records/RecordUtils.js.map +1 -0
- package/dist/src/records/Totp.d.ts +14 -0
- package/dist/src/records/Totp.js +111 -0
- package/dist/src/records/Totp.js.map +1 -0
- package/dist/src/sharedFolders/SharedFolderManager.d.ts +20 -0
- package/dist/src/sharedFolders/SharedFolderManager.js +33 -0
- package/dist/src/sharedFolders/SharedFolderManager.js.map +1 -0
- package/dist/src/sharedFolders/listSharedFolders.d.ts +29 -0
- package/dist/src/sharedFolders/listSharedFolders.js +127 -0
- package/dist/src/sharedFolders/listSharedFolders.js.map +1 -0
- package/dist/src/sharedFolders/shareFolder.d.ts +36 -0
- package/dist/src/sharedFolders/shareFolder.js +352 -0
- package/dist/src/sharedFolders/shareFolder.js.map +1 -0
- package/dist/src/sharing/Sharing.d.ts +50 -0
- package/dist/src/sharing/Sharing.js +195 -0
- package/dist/src/sharing/Sharing.js.map +1 -0
- package/dist/src/storage/InMemoryStorage.d.ts +24 -0
- package/dist/src/storage/InMemoryStorage.js +139 -0
- package/dist/src/storage/InMemoryStorage.js.map +1 -0
- package/dist/src/teams/TeamManager.d.ts +17 -0
- package/dist/src/teams/TeamManager.js +38 -0
- package/dist/src/teams/TeamManager.js.map +1 -0
- package/dist/src/teams/enterpriseData.d.ts +106 -0
- package/dist/src/teams/enterpriseData.js +319 -0
- package/dist/src/teams/enterpriseData.js.map +1 -0
- package/dist/src/teams/listTeams.d.ts +42 -0
- package/dist/src/teams/listTeams.js +308 -0
- package/dist/src/teams/listTeams.js.map +1 -0
- package/dist/src/teams/viewTeam.d.ts +35 -0
- package/dist/src/teams/viewTeam.js +177 -0
- package/dist/src/teams/viewTeam.js.map +1 -0
- package/dist/src/utils/Logger.d.ts +28 -0
- package/dist/src/utils/Logger.js +62 -0
- package/dist/src/utils/Logger.js.map +1 -0
- package/dist/src/utils/constants.d.ts +50 -0
- package/dist/src/utils/constants.js +64 -0
- package/dist/src/utils/constants.js.map +1 -0
- package/dist/src/utils/errors.d.ts +10 -0
- package/dist/src/utils/errors.js +117 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/guards.d.ts +7 -0
- package/dist/src/utils/guards.js +29 -0
- package/dist/src/utils/guards.js.map +1 -0
- package/dist/src/utils/index.d.ts +7 -0
- package/dist/src/utils/index.js +39 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/patterns.d.ts +9 -0
- package/dist/src/utils/patterns.js +20 -0
- package/dist/src/utils/patterns.js.map +1 -0
- package/dist/src/utils/types.d.ts +12 -0
- package/dist/src/utils/types.js +3 -0
- package/dist/src/utils/types.js.map +1 -0
- package/dist/src/vault/KeeperVault.d.ts +116 -0
- package/dist/src/vault/KeeperVault.js +443 -0
- package/dist/src/vault/KeeperVault.js.map +1 -0
- package/dist/storage/InMemoryStorage.d.ts +24 -0
- package/dist/storage/InMemoryStorage.js +132 -0
- package/dist/storage/InMemoryStorage.js.map +1 -0
- package/dist/utils/Logger.d.ts +28 -0
- package/dist/utils/Logger.js +62 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/constants.d.ts +26 -0
- package/dist/utils/constants.js +37 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/errors.d.ts +10 -0
- package/dist/utils/errors.js +117 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +22 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/vault/KeeperVault.d.ts +72 -0
- package/dist/vault/KeeperVault.js +338 -0
- package/dist/vault/KeeperVault.js.map +1 -0
- package/package.json +32 -0
- package/src/auth/ConsoleAuthUI.ts +169 -0
- package/src/auth/ConsoleLogin.ts +351 -0
- package/src/auth/SessionManager.ts +293 -0
- package/src/folders/FolderManager.ts +174 -0
- package/src/folders/addFolder.ts +294 -0
- package/src/folders/changeDirectory.ts +217 -0
- package/src/folders/deleteFolder.ts +293 -0
- package/src/folders/folderHelpers.ts +99 -0
- package/src/folders/folderTree.ts +321 -0
- package/src/folders/getFolder.ts +234 -0
- package/src/folders/listFolder.ts +358 -0
- package/src/folders/updateFolder.ts +210 -0
- package/src/index.ts +242 -0
- package/src/records/RecordOperations.ts +549 -0
- package/src/records/RecordUtils.ts +282 -0
- package/src/records/Totp.ts +119 -0
- package/src/sharedFolders/SharedFolderManager.ts +57 -0
- package/src/sharedFolders/listSharedFolders.ts +173 -0
- package/src/sharedFolders/shareFolder.ts +457 -0
- package/src/sharing/Sharing.ts +282 -0
- package/src/storage/InMemoryStorage.ts +163 -0
- package/src/teams/TeamManager.ts +61 -0
- package/src/teams/enterpriseData.ts +453 -0
- package/src/teams/listTeams.ts +373 -0
- package/src/teams/viewTeam.ts +248 -0
- package/src/utils/Logger.ts +71 -0
- package/src/utils/constants.ts +63 -0
- package/src/utils/errors.ts +108 -0
- package/src/utils/guards.ts +24 -0
- package/src/utils/index.ts +22 -0
- package/src/utils/patterns.ts +20 -0
- package/src/utils/types.ts +11 -0
- package/src/vault/KeeperVault.ts +612 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Auth,
|
|
3
|
+
Records,
|
|
4
|
+
Authentication,
|
|
5
|
+
platform,
|
|
6
|
+
getPublicKeysMessage,
|
|
7
|
+
getRecordsDetailsMessage,
|
|
8
|
+
webSafe64FromBytes,
|
|
9
|
+
recordsShareUpdateMessage,
|
|
10
|
+
normal64Bytes,
|
|
11
|
+
} from '@keeper-security/keeperapi'
|
|
12
|
+
import { extractErrorMessage, KeeperSdkError } from '../utils/errors'
|
|
13
|
+
|
|
14
|
+
enum ShareStatus {
|
|
15
|
+
Success = 'success',
|
|
16
|
+
PendingAccept = 'pending_accept',
|
|
17
|
+
MissingPublicKey = 'missing_public_key',
|
|
18
|
+
Error = 'error',
|
|
19
|
+
Unknown = 'unknown',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ShareRecordInput = {
|
|
23
|
+
recordUid: string
|
|
24
|
+
email: string
|
|
25
|
+
canEdit?: boolean
|
|
26
|
+
canShare?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type ShareRecordResult = {
|
|
30
|
+
recordUid: string
|
|
31
|
+
email: string
|
|
32
|
+
success: boolean
|
|
33
|
+
status: string
|
|
34
|
+
message: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type RemoveShareInput = {
|
|
38
|
+
recordUid: string
|
|
39
|
+
email: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type RemoveShareResult = {
|
|
43
|
+
recordUid: string
|
|
44
|
+
email: string
|
|
45
|
+
success: boolean
|
|
46
|
+
status: string
|
|
47
|
+
message: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type UserKeys = {
|
|
51
|
+
username: string
|
|
52
|
+
rsaPublicKey: Uint8Array | null
|
|
53
|
+
eccPublicKey: Uint8Array | null
|
|
54
|
+
errorCode: string | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function loadUserPublicKey(auth: Auth, email: string): Promise<UserKeys> {
|
|
58
|
+
const msg = getPublicKeysMessage({ usernames: [email] })
|
|
59
|
+
let response: Authentication.IGetPublicKeysResponse
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
response = await auth.executeRest(msg)
|
|
63
|
+
} catch (err) {
|
|
64
|
+
throw new KeeperSdkError(`Failed to fetch public key for ${email}: ${extractErrorMessage(err)}`)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const keyResponses = response.keyResponses || []
|
|
68
|
+
if (keyResponses.length === 0) {
|
|
69
|
+
throw new KeeperSdkError(`No public key returned for ${email}`, 'missing_public_key')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const entry = keyResponses[0]
|
|
73
|
+
if (entry.errorCode) {
|
|
74
|
+
throw new KeeperSdkError(
|
|
75
|
+
`Public key lookup failed for ${email}: ${entry.errorCode} - ${entry.message || ''}`,
|
|
76
|
+
entry.errorCode
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
username: entry.username || email,
|
|
82
|
+
rsaPublicKey: entry.publicKey && entry.publicKey.length > 0 ? (entry.publicKey as Uint8Array) : null,
|
|
83
|
+
eccPublicKey: entry.publicEccKey && entry.publicEccKey.length > 0 ? (entry.publicEccKey as Uint8Array) : null,
|
|
84
|
+
errorCode: entry.errorCode || null,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function shareRecord(
|
|
89
|
+
auth: Auth,
|
|
90
|
+
recordKey: Uint8Array,
|
|
91
|
+
input: ShareRecordInput
|
|
92
|
+
): Promise<ShareRecordResult> {
|
|
93
|
+
const { recordUid, email, canEdit = false, canShare = false } = input
|
|
94
|
+
|
|
95
|
+
const userKeys = await loadUserPublicKey(auth, email)
|
|
96
|
+
|
|
97
|
+
let encryptedRecordKey: Uint8Array
|
|
98
|
+
let useEccKey = false
|
|
99
|
+
|
|
100
|
+
if (userKeys.eccPublicKey) {
|
|
101
|
+
encryptedRecordKey = await platform.publicEncryptEC(recordKey, userKeys.eccPublicKey)
|
|
102
|
+
useEccKey = true
|
|
103
|
+
} else if (userKeys.rsaPublicKey) {
|
|
104
|
+
const rsaKeyBase64 = platform.bytesToBase64(userKeys.rsaPublicKey)
|
|
105
|
+
encryptedRecordKey = platform.publicEncrypt(recordKey, rsaKeyBase64)
|
|
106
|
+
useEccKey = false
|
|
107
|
+
} else {
|
|
108
|
+
return {
|
|
109
|
+
recordUid,
|
|
110
|
+
email,
|
|
111
|
+
success: false,
|
|
112
|
+
status: ShareStatus.MissingPublicKey,
|
|
113
|
+
message: `No usable public key available for ${email}`,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const sharedRecord: Records.ISharedRecord = {
|
|
118
|
+
toUsername: email,
|
|
119
|
+
recordUid: normal64Bytes(recordUid),
|
|
120
|
+
recordKey: encryptedRecordKey,
|
|
121
|
+
editable: canEdit,
|
|
122
|
+
shareable: canShare,
|
|
123
|
+
useEccKey,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const msg = recordsShareUpdateMessage({ addSharedRecord: [sharedRecord] })
|
|
127
|
+
|
|
128
|
+
let response: Records.IRecordShareUpdateResponse
|
|
129
|
+
try {
|
|
130
|
+
response = await auth.executeRest(msg)
|
|
131
|
+
} catch (err) {
|
|
132
|
+
return {
|
|
133
|
+
recordUid,
|
|
134
|
+
email,
|
|
135
|
+
success: false,
|
|
136
|
+
status: ShareStatus.Error,
|
|
137
|
+
message: extractErrorMessage(err),
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const addStatuses = response.addSharedRecordStatus || []
|
|
142
|
+
if (addStatuses.length > 0) {
|
|
143
|
+
const st = addStatuses[0]
|
|
144
|
+
const isSuccess = st.status === ShareStatus.Success || st.status === ShareStatus.PendingAccept
|
|
145
|
+
return {
|
|
146
|
+
recordUid,
|
|
147
|
+
email: st.username || email,
|
|
148
|
+
success: isSuccess,
|
|
149
|
+
status: st.status || ShareStatus.Unknown,
|
|
150
|
+
message: st.message || st.status || '',
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
recordUid,
|
|
156
|
+
email,
|
|
157
|
+
success: true,
|
|
158
|
+
status: ShareStatus.Success,
|
|
159
|
+
message: 'Record shared successfully',
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function removeRecordShare(auth: Auth, input: RemoveShareInput): Promise<RemoveShareResult> {
|
|
164
|
+
const { recordUid, email } = input
|
|
165
|
+
|
|
166
|
+
const msg = recordsShareUpdateMessage({
|
|
167
|
+
removeSharedRecord: [
|
|
168
|
+
{
|
|
169
|
+
toUsername: email,
|
|
170
|
+
recordUid: normal64Bytes(recordUid),
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
let response: Records.IRecordShareUpdateResponse
|
|
176
|
+
try {
|
|
177
|
+
response = await auth.executeRest(msg)
|
|
178
|
+
} catch (err) {
|
|
179
|
+
return {
|
|
180
|
+
recordUid,
|
|
181
|
+
email,
|
|
182
|
+
success: false,
|
|
183
|
+
status: ShareStatus.Error,
|
|
184
|
+
message: extractErrorMessage(err),
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const removeStatuses = response.removeSharedRecordStatus || []
|
|
189
|
+
if (removeStatuses.length > 0) {
|
|
190
|
+
const st = removeStatuses[0]
|
|
191
|
+
return {
|
|
192
|
+
recordUid,
|
|
193
|
+
email: st.username || email,
|
|
194
|
+
success: st.status === ShareStatus.Success,
|
|
195
|
+
status: st.status || ShareStatus.Unknown,
|
|
196
|
+
message: st.message || st.status || '',
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
recordUid,
|
|
202
|
+
email,
|
|
203
|
+
success: true,
|
|
204
|
+
status: ShareStatus.Success,
|
|
205
|
+
message: 'Share removed successfully',
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export type RecordUserPermission = {
|
|
210
|
+
username: string
|
|
211
|
+
accountUid?: string
|
|
212
|
+
owner: boolean
|
|
213
|
+
shareAdmin: boolean
|
|
214
|
+
shareable: boolean
|
|
215
|
+
editable: boolean
|
|
216
|
+
awaitingApproval: boolean
|
|
217
|
+
expiration?: number
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export type RecordSharedFolderPermission = {
|
|
221
|
+
sharedFolderUid: string
|
|
222
|
+
resharable: boolean
|
|
223
|
+
editable: boolean
|
|
224
|
+
revision?: number
|
|
225
|
+
expiration?: number
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export type RecordShareInfo = {
|
|
229
|
+
recordUid: string
|
|
230
|
+
userPermissions: RecordUserPermission[]
|
|
231
|
+
sharedFolderPermissions: RecordSharedFolderPermission[]
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function bytesToUid(bytes: Uint8Array | null | undefined): string | undefined {
|
|
235
|
+
return bytes && bytes.length > 0 ? webSafe64FromBytes(bytes) : undefined
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function longToNumber(value: number | { toNumber: () => number } | null | undefined): number | undefined {
|
|
239
|
+
if (value == null) return undefined
|
|
240
|
+
return typeof value === 'number' ? value : value.toNumber()
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export async function getRecordShareInfo(auth: Auth, recordUid: string): Promise<RecordShareInfo | null> {
|
|
244
|
+
const msg = getRecordsDetailsMessage({
|
|
245
|
+
clientTime: Date.now(),
|
|
246
|
+
recordUid: [normal64Bytes(recordUid)],
|
|
247
|
+
recordDetailsInclude: Records.RecordDetailsInclude.SHARE_ONLY,
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
let response: Records.IGetRecordDataWithAccessInfoResponse
|
|
251
|
+
try {
|
|
252
|
+
response = await auth.executeRest(msg)
|
|
253
|
+
} catch (err) {
|
|
254
|
+
throw new KeeperSdkError(
|
|
255
|
+
`Failed to fetch share info for ${recordUid}: ${extractErrorMessage(err)}`
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const detail = response.recordDataWithAccessInfo?.[0]
|
|
260
|
+
if (!detail) return null
|
|
261
|
+
|
|
262
|
+
const userPermissions: RecordUserPermission[] = (detail.userPermission ?? []).map((u) => ({
|
|
263
|
+
username: u.username || '',
|
|
264
|
+
accountUid: bytesToUid(u.accountUid),
|
|
265
|
+
owner: !!u.owner,
|
|
266
|
+
shareAdmin: !!u.shareAdmin,
|
|
267
|
+
shareable: !!u.sharable,
|
|
268
|
+
editable: !!u.editable,
|
|
269
|
+
awaitingApproval: !!u.awaitingApproval,
|
|
270
|
+
expiration: longToNumber(u.expiration as number | null | undefined),
|
|
271
|
+
}))
|
|
272
|
+
|
|
273
|
+
const sharedFolderPermissions: RecordSharedFolderPermission[] = (detail.sharedFolderPermission ?? []).map((s) => ({
|
|
274
|
+
sharedFolderUid: bytesToUid(s.sharedFolderUid) ?? '',
|
|
275
|
+
resharable: !!s.resharable,
|
|
276
|
+
editable: !!s.editable,
|
|
277
|
+
revision: longToNumber(s.revision as number | null | undefined),
|
|
278
|
+
expiration: longToNumber(s.expiration as number | null | undefined),
|
|
279
|
+
}))
|
|
280
|
+
|
|
281
|
+
return { recordUid, userPermissions, sharedFolderPermissions }
|
|
282
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
VaultStorage,
|
|
3
|
+
VaultStorageData,
|
|
4
|
+
VaultStorageKind,
|
|
5
|
+
VaultStorageResult,
|
|
6
|
+
Dependency,
|
|
7
|
+
Dependencies,
|
|
8
|
+
RemovedDependencies,
|
|
9
|
+
DRecord,
|
|
10
|
+
} from '@keeper-security/keeperapi'
|
|
11
|
+
import { webSafe64FromBytes } from '@keeper-security/keeperapi'
|
|
12
|
+
import { VaultObjectKind } from '../folders/folderHelpers'
|
|
13
|
+
|
|
14
|
+
export class InMemoryStorage implements VaultStorage {
|
|
15
|
+
private keys = new Map<string, Uint8Array>()
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- KeyStorage.saveObject<T> is unconstrained
|
|
17
|
+
private objects = new Map<string, any>()
|
|
18
|
+
private store = new Map<string, Map<string, VaultStorageData>>()
|
|
19
|
+
private dependenciesByParent = new Map<string, Dependency[]>()
|
|
20
|
+
private arrayCache = new Map<string, VaultStorageData[]>()
|
|
21
|
+
|
|
22
|
+
public async getKeyBytes(keyId: string): Promise<Uint8Array | undefined> {
|
|
23
|
+
return this.keys.get(keyId)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async saveKeyBytes(keyId: string, key: Uint8Array): Promise<void> {
|
|
27
|
+
this.keys.set(keyId, key)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async getObject<T>(key: string): Promise<T | undefined> {
|
|
31
|
+
return this.objects.get(key) as T | undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async saveObject<T>(key: string, value: T): Promise<void> {
|
|
35
|
+
this.objects.set(key, value)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async put(item: VaultStorageData): Promise<void> {
|
|
39
|
+
const kind = item.kind
|
|
40
|
+
if (!this.store.has(kind)) {
|
|
41
|
+
this.store.set(kind, new Map())
|
|
42
|
+
}
|
|
43
|
+
const uid = this.extractUid(item)
|
|
44
|
+
this.store.get(kind)!.set(uid, item)
|
|
45
|
+
this.arrayCache.delete(kind)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async get<T extends VaultStorageKind>(kind: T, uid?: string): Promise<VaultStorageResult<T>> {
|
|
49
|
+
const kindMap = this.store.get(kind)
|
|
50
|
+
if (!kindMap) return undefined as VaultStorageResult<T>
|
|
51
|
+
|
|
52
|
+
if (uid) {
|
|
53
|
+
return kindMap.get(uid) as VaultStorageResult<T>
|
|
54
|
+
}
|
|
55
|
+
const first = kindMap.values().next()
|
|
56
|
+
return (first.done ? undefined : first.value) as VaultStorageResult<T>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public async delete(kind: VaultStorageKind, uid: string | Uint8Array): Promise<void> {
|
|
60
|
+
const uidStr = typeof uid === 'string' ? uid : webSafe64FromBytes(uid)
|
|
61
|
+
this.store.get(kind)?.delete(uidStr)
|
|
62
|
+
this.arrayCache.delete(kind)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async clear(): Promise<void> {
|
|
66
|
+
this.store.clear()
|
|
67
|
+
this.keys.clear()
|
|
68
|
+
this.objects.clear()
|
|
69
|
+
this.dependenciesByParent.clear()
|
|
70
|
+
this.arrayCache.clear()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public async getDependencies(uid: string): Promise<Dependency[] | undefined> {
|
|
74
|
+
return this.dependenciesByParent.get(uid)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public async addDependencies(dependencies: Dependencies): Promise<void> {
|
|
78
|
+
for (const [parentUid, children] of Object.entries(dependencies)) {
|
|
79
|
+
if (!this.dependenciesByParent.has(parentUid)) {
|
|
80
|
+
this.dependenciesByParent.set(parentUid, [])
|
|
81
|
+
}
|
|
82
|
+
const existing = this.dependenciesByParent.get(parentUid)!
|
|
83
|
+
const seenChildUids = new Set(existing.map((dependency) => dependency.uid))
|
|
84
|
+
for (const child of children) {
|
|
85
|
+
if (!seenChildUids.has(child.uid)) {
|
|
86
|
+
existing.push(child)
|
|
87
|
+
seenChildUids.add(child.uid)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public async removeDependencies(dependencies: RemovedDependencies): Promise<void> {
|
|
94
|
+
for (const [parentUid, children] of Object.entries(dependencies)) {
|
|
95
|
+
if (children === '*') {
|
|
96
|
+
this.dependenciesByParent.delete(parentUid)
|
|
97
|
+
} else {
|
|
98
|
+
const existing = this.dependenciesByParent.get(parentUid)
|
|
99
|
+
if (existing) {
|
|
100
|
+
const removeSet = children as Set<string>
|
|
101
|
+
this.dependenciesByParent.set(
|
|
102
|
+
parentUid,
|
|
103
|
+
existing.filter((dependency) => !removeSet.has(dependency.uid))
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public getAll<T extends VaultStorageData>(kind: VaultStorageKind): T[] {
|
|
111
|
+
const cached = this.arrayCache.get(kind)
|
|
112
|
+
if (cached) return cached as T[]
|
|
113
|
+
|
|
114
|
+
const kindMap = this.store.get(kind)
|
|
115
|
+
if (!kindMap) return []
|
|
116
|
+
|
|
117
|
+
const arr = Array.from(kindMap.values())
|
|
118
|
+
this.arrayCache.set(kind, arr)
|
|
119
|
+
return arr as T[]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public getRecords(): DRecord[] {
|
|
123
|
+
return this.getAll<DRecord>(VaultObjectKind.Record)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public getByUid<T extends VaultStorageData>(kind: VaultStorageKind, uid: string): T | undefined {
|
|
127
|
+
return this.store.get(kind)?.get(uid) as T | undefined
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public getCount(kind: VaultStorageKind): number {
|
|
131
|
+
return this.store.get(kind)?.size ?? 0
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private extractUid(item: VaultStorageData): string {
|
|
135
|
+
const record = item as VaultStorageData & {
|
|
136
|
+
uid?: string
|
|
137
|
+
token?: string
|
|
138
|
+
sharedFolderUid?: string
|
|
139
|
+
recordUid?: string
|
|
140
|
+
accountUid?: string | Uint8Array
|
|
141
|
+
teamUid?: string
|
|
142
|
+
}
|
|
143
|
+
const accountUidStr =
|
|
144
|
+
typeof record.accountUid === 'string'
|
|
145
|
+
? record.accountUid
|
|
146
|
+
: record.accountUid instanceof Uint8Array
|
|
147
|
+
? webSafe64FromBytes(record.accountUid)
|
|
148
|
+
: undefined
|
|
149
|
+
if (record.uid) return record.uid
|
|
150
|
+
if (record.token) return record.token
|
|
151
|
+
if (record.sharedFolderUid && record.recordUid) {
|
|
152
|
+
return `${record.sharedFolderUid}:${record.recordUid}`
|
|
153
|
+
}
|
|
154
|
+
if (record.sharedFolderUid && accountUidStr) {
|
|
155
|
+
return `${record.sharedFolderUid}:${accountUidStr}`
|
|
156
|
+
}
|
|
157
|
+
if (record.sharedFolderUid && record.teamUid) {
|
|
158
|
+
return `${record.sharedFolderUid}:${record.teamUid}`
|
|
159
|
+
}
|
|
160
|
+
if (item.kind === VaultObjectKind.User && accountUidStr) return accountUidStr
|
|
161
|
+
return '_singleton_'
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Auth } from '@keeper-security/keeperapi'
|
|
2
|
+
import { KeeperSdkError, ResultCodes } from '../utils'
|
|
3
|
+
import {
|
|
4
|
+
formatTeamsTable,
|
|
5
|
+
listTeams,
|
|
6
|
+
renderTeamsAsciiTable,
|
|
7
|
+
type FormatTeamsTableOptions,
|
|
8
|
+
type FormattedTeamsTable,
|
|
9
|
+
type ListTeamRow,
|
|
10
|
+
type ListTeamsOptions,
|
|
11
|
+
} from './listTeams'
|
|
12
|
+
import {
|
|
13
|
+
formatTeamView,
|
|
14
|
+
teamViewTable,
|
|
15
|
+
viewTeam,
|
|
16
|
+
type FormatTeamViewOptions,
|
|
17
|
+
type FormattedTeamViewTable,
|
|
18
|
+
type TeamView,
|
|
19
|
+
} from './viewTeam'
|
|
20
|
+
|
|
21
|
+
export type AuthProvider = () => Auth
|
|
22
|
+
|
|
23
|
+
export class TeamManager {
|
|
24
|
+
private readonly authProvider: AuthProvider
|
|
25
|
+
|
|
26
|
+
constructor(authProvider: AuthProvider) {
|
|
27
|
+
this.authProvider = authProvider
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async listTeams(options: ListTeamsOptions = {}): Promise<ListTeamRow[]> {
|
|
31
|
+
return listTeams(this.requireAuth(), options)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public formatTeamsTable(rows: ListTeamRow[], options: FormatTeamsTableOptions = {}): FormattedTeamsTable {
|
|
35
|
+
return formatTeamsTable(rows, options)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public renderTeamsAsciiTable(table: FormattedTeamsTable, options: { minColWidth?: number } = {}): string {
|
|
39
|
+
return renderTeamsAsciiTable(table, options)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async viewTeam(identifier: string): Promise<TeamView> {
|
|
43
|
+
return viewTeam(this.requireAuth(), identifier)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public formatTeamView(view: TeamView, options: FormatTeamViewOptions = {}): FormattedTeamViewTable {
|
|
47
|
+
return formatTeamView(view, options)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public teamViewTable(table: FormattedTeamViewTable): string {
|
|
51
|
+
return teamViewTable(table)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private requireAuth(): Auth {
|
|
55
|
+
const auth = this.authProvider()
|
|
56
|
+
if (!auth) {
|
|
57
|
+
throw new KeeperSdkError('You are not logged in. Please log in first.', ResultCodes.NOT_LOGGED_IN)
|
|
58
|
+
}
|
|
59
|
+
return auth
|
|
60
|
+
}
|
|
61
|
+
}
|