@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,612 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Auth,
|
|
3
|
+
KeeperEnvironment,
|
|
4
|
+
syncDown,
|
|
5
|
+
DRecord,
|
|
6
|
+
DRecordMetadata,
|
|
7
|
+
DSharedFolder,
|
|
8
|
+
DTeam,
|
|
9
|
+
DUserFolder,
|
|
10
|
+
Authentication,
|
|
11
|
+
} from '@keeper-security/keeperapi'
|
|
12
|
+
import type { SyncResult, SyncLogFormat, VaultStorage, SessionStorage, AuthUI3 } from '@keeper-security/keeperapi'
|
|
13
|
+
import { InMemoryStorage } from '../storage/InMemoryStorage'
|
|
14
|
+
import { SessionManager } from '../auth/SessionManager'
|
|
15
|
+
import { ConsoleAuthUI } from '../auth/ConsoleAuthUI'
|
|
16
|
+
import { searchRecords, formatRecord, getRecordTitle, getRecordType } from '../records/RecordUtils'
|
|
17
|
+
import {
|
|
18
|
+
addRecord as addRecordOp,
|
|
19
|
+
updateRecord as updateRecordOp,
|
|
20
|
+
deleteRecord as deleteRecordOp,
|
|
21
|
+
getRecordHistory as getRecordHistoryOp,
|
|
22
|
+
moveRecord as moveRecordOp,
|
|
23
|
+
} from '../records/RecordOperations'
|
|
24
|
+
import type {
|
|
25
|
+
NewRecordInput,
|
|
26
|
+
TypedRecordData,
|
|
27
|
+
AddRecordResult,
|
|
28
|
+
UpdateRecordResult,
|
|
29
|
+
DeleteRecordResult,
|
|
30
|
+
RecordHistoryResult,
|
|
31
|
+
MoveRecordInput,
|
|
32
|
+
MoveRecordResult,
|
|
33
|
+
} from '../records/RecordOperations'
|
|
34
|
+
import {
|
|
35
|
+
shareRecord as shareRecordOp,
|
|
36
|
+
removeRecordShare as removeRecordShareOp,
|
|
37
|
+
getRecordShareInfo as getRecordShareInfoOp,
|
|
38
|
+
} from '../sharing/Sharing'
|
|
39
|
+
import type {
|
|
40
|
+
ShareRecordInput,
|
|
41
|
+
ShareRecordResult,
|
|
42
|
+
RemoveShareInput,
|
|
43
|
+
RemoveShareResult,
|
|
44
|
+
RecordShareInfo,
|
|
45
|
+
} from '../sharing/Sharing'
|
|
46
|
+
import type { ListFolderOptions, ListFolderResult } from '../folders/listFolder'
|
|
47
|
+
import { FolderKind, VaultObjectKind } from '../folders/folderHelpers'
|
|
48
|
+
import type { ChangeDirectoryResult, VaultFolderSession } from '../folders/changeDirectory'
|
|
49
|
+
import type { AddFolderInput, AddFolderResult, MkdirOptions } from '../folders/addFolder'
|
|
50
|
+
import type { UpdateFolderInput, UpdateFolderResult, RenameFolderResult } from '../folders/updateFolder'
|
|
51
|
+
import type { DeleteFolderResult, RmdirOptions } from '../folders/deleteFolder'
|
|
52
|
+
import type { FolderTreeBuildOptions } from '../folders/folderTree'
|
|
53
|
+
import type { GetFolderOptions, GetFolderResult } from '../folders/getFolder'
|
|
54
|
+
import type { ListSharedFolderRow, ListSharedFoldersOptions } from '../sharedFolders/listSharedFolders'
|
|
55
|
+
import type { ShareFolderInput, ShareFolderResult } from '../sharedFolders/shareFolder'
|
|
56
|
+
import { FolderManager } from '../folders/FolderManager'
|
|
57
|
+
import type { SharedFolderPermissionsInput } from '../folders/FolderManager'
|
|
58
|
+
import { SharedFolderManager } from '../sharedFolders/SharedFolderManager'
|
|
59
|
+
import { TeamManager } from '../teams/TeamManager'
|
|
60
|
+
import type { ListTeamRow, ListTeamsOptions } from '../teams/listTeams'
|
|
61
|
+
import type { TeamView } from '../teams/viewTeam'
|
|
62
|
+
import { ConsoleLogger, LogLevel, KeeperSdkError, extractErrorMessage, SdkDefaults, ResultCodes } from '../utils'
|
|
63
|
+
import type { ILogger } from '../utils'
|
|
64
|
+
|
|
65
|
+
enum VaultStatus {
|
|
66
|
+
RecordNotFound = 'RECORD_NOT_FOUND',
|
|
67
|
+
RecordKeyNotFound = 'RECORD_KEY_NOT_FOUND',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type KeeperVaultConfig = {
|
|
71
|
+
host?: string
|
|
72
|
+
clientVersion?: string
|
|
73
|
+
configDir?: string
|
|
74
|
+
useConsoleAuth?: boolean
|
|
75
|
+
logFormat?: SyncLogFormat
|
|
76
|
+
logLevel?: LogLevel
|
|
77
|
+
autoSync?: boolean
|
|
78
|
+
storage?: InMemoryStorage
|
|
79
|
+
sessionStorage?: SessionManager
|
|
80
|
+
authUI?: AuthUI3
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type VaultSummary = {
|
|
84
|
+
recordCount: number
|
|
85
|
+
sharedFolderCount: number
|
|
86
|
+
teamCount: number
|
|
87
|
+
folderCount: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class KeeperVault {
|
|
91
|
+
private auth: Auth | null = null
|
|
92
|
+
private readonly storage: InMemoryStorage
|
|
93
|
+
private readonly sessionManager: SessionManager
|
|
94
|
+
private readonly authUI: AuthUI3
|
|
95
|
+
private readonly config: Required<Omit<KeeperVaultConfig, 'storage' | 'sessionStorage' | 'authUI'>>
|
|
96
|
+
private readonly log: ILogger
|
|
97
|
+
private synced = false
|
|
98
|
+
private batchDepth = 0
|
|
99
|
+
private readonly folderSession: VaultFolderSession = FolderManager.createSession()
|
|
100
|
+
private readonly folderManager: FolderManager
|
|
101
|
+
private readonly sharedFolderManager: SharedFolderManager
|
|
102
|
+
private readonly teamManager: TeamManager
|
|
103
|
+
|
|
104
|
+
constructor(config?: KeeperVaultConfig) {
|
|
105
|
+
this.config = {
|
|
106
|
+
host: config?.host || KeeperEnvironment.Prod,
|
|
107
|
+
clientVersion: config?.clientVersion || SdkDefaults.CLIENT_VERSION,
|
|
108
|
+
configDir: config?.configDir ?? '',
|
|
109
|
+
useConsoleAuth: config?.useConsoleAuth !== false,
|
|
110
|
+
logFormat: config?.logFormat || SdkDefaults.LOG_FORMAT,
|
|
111
|
+
logLevel: config?.logLevel ?? LogLevel.INFO,
|
|
112
|
+
autoSync: config?.autoSync !== false,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.log = new ConsoleLogger(this.config.logLevel)
|
|
116
|
+
this.storage = config?.storage || new InMemoryStorage()
|
|
117
|
+
this.sessionManager = config?.sessionStorage || new SessionManager(this.config.configDir || undefined)
|
|
118
|
+
this.authUI = config?.authUI || new ConsoleAuthUI()
|
|
119
|
+
|
|
120
|
+
const authProvider = () => this.getAuthOrThrow()
|
|
121
|
+
this.folderManager = new FolderManager(this.storage, this.folderSession, authProvider)
|
|
122
|
+
this.sharedFolderManager = new SharedFolderManager(this.storage, authProvider)
|
|
123
|
+
this.teamManager = new TeamManager(authProvider)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public getFolderManager(): FolderManager {
|
|
127
|
+
return this.folderManager
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public getSharedFolderManager(): SharedFolderManager {
|
|
131
|
+
return this.sharedFolderManager
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public getTeamManager(): TeamManager {
|
|
135
|
+
return this.teamManager
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private async createAuth(options?: { useSessionResumption?: boolean }): Promise<Auth> {
|
|
139
|
+
const host = this.config.host
|
|
140
|
+
const baseDeviceConfig = await this.sessionManager.getDeviceConfig(host)
|
|
141
|
+
const deviceConfig = {
|
|
142
|
+
...baseDeviceConfig,
|
|
143
|
+
deviceName: baseDeviceConfig.deviceName || SdkDefaults.DEVICE_NAME,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const sessionStorage: SessionStorage =
|
|
147
|
+
options?.useSessionResumption === false
|
|
148
|
+
? {
|
|
149
|
+
getCloneCode: async () => null,
|
|
150
|
+
saveCloneCode: (h, u, c) => this.sessionManager.saveCloneCode(h, u, c),
|
|
151
|
+
getSessionParameters: () => this.sessionManager.getSessionParameters(),
|
|
152
|
+
saveSessionParameters: (p) => this.sessionManager.saveSessionParameters(p),
|
|
153
|
+
}
|
|
154
|
+
: this.sessionManager
|
|
155
|
+
|
|
156
|
+
return new Auth({
|
|
157
|
+
host,
|
|
158
|
+
clientVersion: this.config.clientVersion,
|
|
159
|
+
deviceConfig,
|
|
160
|
+
authUI3: this.config.useConsoleAuth ? this.authUI : undefined,
|
|
161
|
+
sessionStorage,
|
|
162
|
+
onDeviceConfig: this.sessionManager.createOnDeviceConfig(host),
|
|
163
|
+
useSessionResumption: options?.useSessionResumption,
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private getAuthOrThrow(): Auth {
|
|
168
|
+
if (!this.auth || !this.auth.sessionToken) {
|
|
169
|
+
throw new KeeperSdkError('Not logged in. Call login() first.', ResultCodes.NOT_LOGGED_IN)
|
|
170
|
+
}
|
|
171
|
+
return this.auth
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public async login(username: string, password: string): Promise<void> {
|
|
175
|
+
this.auth = await this.createAuth({ useSessionResumption: false })
|
|
176
|
+
this.sessionManager.setLastUsername(username)
|
|
177
|
+
|
|
178
|
+
await this.auth.loginV3({
|
|
179
|
+
username,
|
|
180
|
+
password,
|
|
181
|
+
loginType: Authentication.LoginType.NORMAL,
|
|
182
|
+
loginMethod: Authentication.LoginMethod.EXISTING_ACCOUNT,
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
this.synced = false
|
|
186
|
+
this.log.info(`Logged in as ${username}`)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public async loginWithSessionToken(username: string, sessionToken: string): Promise<void> {
|
|
190
|
+
const deviceConfig = await this.sessionManager.getDeviceConfig(this.config.host)
|
|
191
|
+
|
|
192
|
+
if (!deviceConfig.deviceToken || !deviceConfig.privateKey) {
|
|
193
|
+
throw new KeeperSdkError(
|
|
194
|
+
'Device is not registered for this host. Perform a normal login first to register the device before using session token login.',
|
|
195
|
+
ResultCodes.DEVICE_NOT_REGISTERED
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.auth = await this.createAuth()
|
|
200
|
+
this.sessionManager.setLastUsername(username)
|
|
201
|
+
|
|
202
|
+
await this.auth.loginV3({
|
|
203
|
+
username,
|
|
204
|
+
givenSessionToken: sessionToken,
|
|
205
|
+
loginType: Authentication.LoginType.NORMAL,
|
|
206
|
+
loginMethod: Authentication.LoginMethod.EXISTING_ACCOUNT,
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
if (!this.auth.sessionToken) {
|
|
210
|
+
throw new KeeperSdkError(
|
|
211
|
+
'Session token login failed — token may be expired or invalid.',
|
|
212
|
+
ResultCodes.SESSION_TOKEN_EXPIRED
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.synced = false
|
|
217
|
+
this.log.info(`Logged in as ${username} (via session token)`)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public getSessionToken(): string | undefined {
|
|
221
|
+
return this.auth?.sessionToken || undefined
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public async resumeSession(): Promise<void> {
|
|
225
|
+
const username = await this.sessionManager.getLastUsername()
|
|
226
|
+
if (!username) {
|
|
227
|
+
throw new KeeperSdkError(
|
|
228
|
+
'No previous login found. Perform a normal login first.',
|
|
229
|
+
ResultCodes.NO_PREVIOUS_LOGIN
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.sessionManager.setLastUsername(username)
|
|
234
|
+
|
|
235
|
+
const deviceConfig = await this.sessionManager.getDeviceConfig(this.config.host)
|
|
236
|
+
if (!deviceConfig.deviceToken || !deviceConfig.privateKey) {
|
|
237
|
+
throw new KeeperSdkError(
|
|
238
|
+
'Device is not registered for this host. Perform a normal login first.',
|
|
239
|
+
ResultCodes.DEVICE_NOT_REGISTERED
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const cloneCode = await this.sessionManager.getCloneCode(this.config.host, username)
|
|
244
|
+
if (!cloneCode) {
|
|
245
|
+
throw new KeeperSdkError(
|
|
246
|
+
'No clone code found. Persistent login not enabled or clone code expired. Perform a normal login.',
|
|
247
|
+
ResultCodes.NO_CLONE_CODE
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
this.auth = await this.createAuth({ useSessionResumption: true })
|
|
252
|
+
|
|
253
|
+
await this.auth.loginV3({
|
|
254
|
+
loginType: Authentication.LoginType.NORMAL,
|
|
255
|
+
resumeSessionOnly: true,
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
if (!this.auth.sessionToken) {
|
|
259
|
+
throw new KeeperSdkError(
|
|
260
|
+
'Persistent login failed — clone code may be expired or persistent login not enabled. Perform a normal login.',
|
|
261
|
+
ResultCodes.PERSISTENT_LOGIN_FAILED
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this.synced = false
|
|
266
|
+
this.log.info(`Session resumed for ${username} (persistent login)`)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public async sync(): Promise<SyncResult> {
|
|
270
|
+
const auth = this.getAuthOrThrow()
|
|
271
|
+
|
|
272
|
+
const result = await syncDown({
|
|
273
|
+
auth,
|
|
274
|
+
storage: this.storage,
|
|
275
|
+
logFormat: this.config.logFormat,
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
this.synced = true
|
|
279
|
+
return result
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
public async batch(fn: () => Promise<void>): Promise<void> {
|
|
283
|
+
this.batchDepth++
|
|
284
|
+
try {
|
|
285
|
+
await fn()
|
|
286
|
+
} finally {
|
|
287
|
+
this.batchDepth--
|
|
288
|
+
if (this.batchDepth === 0 && this.config.autoSync) {
|
|
289
|
+
await this.sync()
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private async syncIfNeeded(): Promise<void> {
|
|
295
|
+
if (this.batchDepth > 0) {
|
|
296
|
+
this.synced = false
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
if (this.config.autoSync) {
|
|
300
|
+
await this.sync()
|
|
301
|
+
} else {
|
|
302
|
+
this.synced = false
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public getRecords(): DRecord[] {
|
|
307
|
+
return this.storage.getRecords()
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public getRecordByUid(uid: string): DRecord | undefined {
|
|
311
|
+
return this.storage.getByUid<DRecord>(VaultObjectKind.Record, uid)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public findRecord(uidOrTitle: string): DRecord | undefined {
|
|
315
|
+
const byUid = this.getRecordByUid(uidOrTitle)
|
|
316
|
+
if (byUid) return byUid
|
|
317
|
+
|
|
318
|
+
const lowerUidOrTitle = uidOrTitle.toLowerCase()
|
|
319
|
+
return this.getRecords().find((record) => getRecordTitle(record).toLowerCase() === lowerUidOrTitle)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public findRecords(criteria: string): DRecord[] {
|
|
323
|
+
return searchRecords(this.getRecords(), criteria)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public getRecordsByVersion(version: number): DRecord[] {
|
|
327
|
+
return this.getRecords().filter((record) => record.version === version)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
public getRecordsByType(recordType: string): DRecord[] {
|
|
331
|
+
return this.getRecords().filter((record) => getRecordType(record) === recordType)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
public getRecordMetadata(): DRecordMetadata[] {
|
|
335
|
+
return this.storage.getAll<DRecordMetadata>(VaultObjectKind.Metadata)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
public getRecordMetadataByUid(uid: string): DRecordMetadata | undefined {
|
|
339
|
+
return this.storage.getByUid<DRecordMetadata>(VaultObjectKind.Metadata, uid)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public getSharedFolders(): DSharedFolder[] {
|
|
343
|
+
return this.storage.getAll<DSharedFolder>(FolderKind.SharedFolder)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public getTeams(): DTeam[] {
|
|
347
|
+
return this.storage.getAll<DTeam>(VaultObjectKind.Team)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
public getUserFolders(): DUserFolder[] {
|
|
351
|
+
return this.storage.getAll<DUserFolder>(FolderKind.UserFolder)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
public async listFolder(options?: ListFolderOptions): Promise<ListFolderResult> {
|
|
355
|
+
return this.folderManager.listFolder(options ?? {})
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
public listSharedFolders(options?: ListSharedFoldersOptions): ListSharedFolderRow[] {
|
|
359
|
+
return this.sharedFolderManager.listSharedFolders(options ?? {})
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
public async listTeams(options?: ListTeamsOptions): Promise<ListTeamRow[]> {
|
|
363
|
+
return this.teamManager.listTeams(options ?? {})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
public async viewTeam(identifier: string): Promise<TeamView> {
|
|
367
|
+
return this.teamManager.viewTeam(identifier)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
public async changeDirectory(path: string): Promise<ChangeDirectoryResult> {
|
|
371
|
+
return this.folderManager.changeDirectory(path)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
public getCurrentFolderUid(): string | null {
|
|
375
|
+
return this.folderManager.getCurrentFolderUid()
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
public getWorkingFolderDisplayName(): string {
|
|
379
|
+
return this.folderManager.getWorkingFolderDisplayName()
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public async getFolder(uidOrName: string, options?: GetFolderOptions): Promise<GetFolderResult> {
|
|
383
|
+
return this.folderManager.getFolder(uidOrName, options ?? {})
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
public async addFolder(input: AddFolderInput): Promise<AddFolderResult> {
|
|
387
|
+
const result = await this.folderManager.addFolder(input)
|
|
388
|
+
if (result.success) await this.syncIfNeeded()
|
|
389
|
+
return result
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
public async mkdir(
|
|
393
|
+
path: string,
|
|
394
|
+
options?: MkdirOptions
|
|
395
|
+
): Promise<{ folderUid: string; success: boolean; message?: string }> {
|
|
396
|
+
const result = await this.folderManager.mkdir(path, options ?? {})
|
|
397
|
+
if (result.success) await this.syncIfNeeded()
|
|
398
|
+
return result
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
public async updateFolder(input: UpdateFolderInput): Promise<UpdateFolderResult> {
|
|
402
|
+
const result = await this.folderManager.updateFolder(input)
|
|
403
|
+
if (result.success) await this.syncIfNeeded()
|
|
404
|
+
return result
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
public async renameFolder(folderPath: string, newName: string): Promise<RenameFolderResult> {
|
|
408
|
+
const result = await this.folderManager.renameFolder(folderPath, newName)
|
|
409
|
+
if (result.success) await this.syncIfNeeded()
|
|
410
|
+
return result
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
public async updateSharedFolderPermissions(
|
|
414
|
+
sharedFolderUid: string,
|
|
415
|
+
permissions: SharedFolderPermissionsInput
|
|
416
|
+
): Promise<UpdateFolderResult> {
|
|
417
|
+
const result = await this.folderManager.updateSharedFolderPermissions(sharedFolderUid, permissions)
|
|
418
|
+
if (result.success) await this.syncIfNeeded()
|
|
419
|
+
return result
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public async deleteFolder(
|
|
423
|
+
folderRefs: string[],
|
|
424
|
+
confirm?: (summary: string) => boolean | Promise<boolean>
|
|
425
|
+
): Promise<DeleteFolderResult> {
|
|
426
|
+
const result = await this.folderManager.deleteFolder(folderRefs, confirm)
|
|
427
|
+
if (result.success) await this.syncIfNeeded()
|
|
428
|
+
return result
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
public async rmdir(patterns: string[], options?: RmdirOptions): Promise<DeleteFolderResult> {
|
|
432
|
+
const result = await this.folderManager.rmdir(patterns, options ?? {})
|
|
433
|
+
if (result.success) await this.syncIfNeeded()
|
|
434
|
+
return result
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
public async tree(options?: FolderTreeBuildOptions): Promise<string> {
|
|
438
|
+
this.getAuthOrThrow()
|
|
439
|
+
return this.folderManager.folderTreeAscii(options ?? {})
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
public getSummary(): VaultSummary {
|
|
443
|
+
return {
|
|
444
|
+
recordCount: this.storage.getCount(VaultObjectKind.Record),
|
|
445
|
+
sharedFolderCount: this.storage.getCount(FolderKind.SharedFolder),
|
|
446
|
+
teamCount: this.storage.getCount(VaultObjectKind.Team),
|
|
447
|
+
folderCount: this.storage.getCount(FolderKind.UserFolder),
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public printRecords(showDetails = false): void {
|
|
452
|
+
const records = this.getRecords()
|
|
453
|
+
if (records.length === 0) {
|
|
454
|
+
this.log.info('No records found in vault.')
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
this.log.info(`\n=== Vault Records (${records.length}) ===\n`)
|
|
458
|
+
for (const record of records) {
|
|
459
|
+
this.log.info(formatRecord(record, showDetails))
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
public async addRecord(input: NewRecordInput): Promise<AddRecordResult> {
|
|
464
|
+
const auth = this.getAuthOrThrow()
|
|
465
|
+
const result = await addRecordOp(auth, input)
|
|
466
|
+
if (result.success) await this.syncIfNeeded()
|
|
467
|
+
return result
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
public async updateRecord(recordUid: string, data: TypedRecordData): Promise<UpdateRecordResult> {
|
|
471
|
+
const auth = this.getAuthOrThrow()
|
|
472
|
+
|
|
473
|
+
const record = this.getRecordByUid(recordUid)
|
|
474
|
+
if (!record) {
|
|
475
|
+
return { recordUid, success: false, status: VaultStatus.RecordNotFound }
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const keyBytes = await this.storage.getKeyBytes(recordUid)
|
|
479
|
+
if (!keyBytes) {
|
|
480
|
+
return {
|
|
481
|
+
recordUid,
|
|
482
|
+
success: false,
|
|
483
|
+
status: VaultStatus.RecordKeyNotFound,
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const result = await updateRecordOp(auth, recordUid, data, record.revision, keyBytes)
|
|
488
|
+
if (result.success) await this.syncIfNeeded()
|
|
489
|
+
return result
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
public async deleteRecord(recordUid: string): Promise<DeleteRecordResult> {
|
|
493
|
+
const auth = this.getAuthOrThrow()
|
|
494
|
+
const result = await deleteRecordOp(auth, recordUid)
|
|
495
|
+
if (result.success) await this.syncIfNeeded()
|
|
496
|
+
return result
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
public async moveRecord(input: MoveRecordInput): Promise<MoveRecordResult> {
|
|
500
|
+
const auth = this.getAuthOrThrow()
|
|
501
|
+
const result = await moveRecordOp(auth, this.storage, input)
|
|
502
|
+
if (result.success) await this.syncIfNeeded()
|
|
503
|
+
return result
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
public async shareRecord(input: ShareRecordInput): Promise<ShareRecordResult> {
|
|
507
|
+
const auth = this.getAuthOrThrow()
|
|
508
|
+
|
|
509
|
+
const record = this.getRecordByUid(input.recordUid) || this.findRecord(input.recordUid)
|
|
510
|
+
if (!record) {
|
|
511
|
+
return {
|
|
512
|
+
recordUid: input.recordUid,
|
|
513
|
+
email: input.email,
|
|
514
|
+
success: false,
|
|
515
|
+
status: VaultStatus.RecordNotFound,
|
|
516
|
+
message: `Record "${input.recordUid}" not found`,
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const keyBytes = await this.storage.getKeyBytes(record.uid)
|
|
521
|
+
if (!keyBytes) {
|
|
522
|
+
return {
|
|
523
|
+
recordUid: record.uid,
|
|
524
|
+
email: input.email,
|
|
525
|
+
success: false,
|
|
526
|
+
status: VaultStatus.RecordKeyNotFound,
|
|
527
|
+
message: 'Record key not available',
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const result = await shareRecordOp(auth, keyBytes, {
|
|
532
|
+
...input,
|
|
533
|
+
recordUid: record.uid,
|
|
534
|
+
})
|
|
535
|
+
if (result.success) await this.syncIfNeeded()
|
|
536
|
+
return result
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
public async removeRecordShare(input: RemoveShareInput): Promise<RemoveShareResult> {
|
|
540
|
+
const auth = this.getAuthOrThrow()
|
|
541
|
+
const result = await removeRecordShareOp(auth, input)
|
|
542
|
+
if (result.success) await this.syncIfNeeded()
|
|
543
|
+
return result
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
public async getRecordShareInfo(recordUid: string): Promise<RecordShareInfo | null> {
|
|
547
|
+
const auth = this.getAuthOrThrow()
|
|
548
|
+
return getRecordShareInfoOp(auth, recordUid)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
public async shareFolder(input: ShareFolderInput): Promise<ShareFolderResult> {
|
|
552
|
+
const result = await this.sharedFolderManager.shareFolder(input)
|
|
553
|
+
if (result.success) await this.syncIfNeeded()
|
|
554
|
+
return result
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
public async getRecordHistory(recordUid: string): Promise<RecordHistoryResult> {
|
|
558
|
+
const auth = this.getAuthOrThrow()
|
|
559
|
+
|
|
560
|
+
const keyBytes = await this.storage.getKeyBytes(recordUid)
|
|
561
|
+
if (!keyBytes) {
|
|
562
|
+
return { recordUid, history: [] }
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return getRecordHistoryOp(auth, recordUid, keyBytes)
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
public getStorage(): VaultStorage {
|
|
569
|
+
return this.storage
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
public getAuth(): Auth {
|
|
573
|
+
return this.getAuthOrThrow()
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
public disconnect(): void {
|
|
577
|
+
if (this.auth) {
|
|
578
|
+
try {
|
|
579
|
+
this.auth.disconnect()
|
|
580
|
+
} catch (err) {
|
|
581
|
+
this.log.debug('disconnect error:', extractErrorMessage(err))
|
|
582
|
+
}
|
|
583
|
+
this.auth = null
|
|
584
|
+
}
|
|
585
|
+
this.synced = false
|
|
586
|
+
this.folderSession.currentFolderUid = null
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
public async logout(): Promise<void> {
|
|
590
|
+
if (this.auth) {
|
|
591
|
+
try {
|
|
592
|
+
await this.auth.logout()
|
|
593
|
+
} catch (err) {
|
|
594
|
+
this.log.debug('logout error:', extractErrorMessage(err))
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
this.disconnect()
|
|
598
|
+
this.log.info('Logged out.')
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
public get host(): string {
|
|
602
|
+
return this.config.host
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
public get isLoggedIn(): boolean {
|
|
606
|
+
return this.auth !== null && !!this.auth.sessionToken
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
public get isSynced(): boolean {
|
|
610
|
+
return this.synced
|
|
611
|
+
}
|
|
612
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"target": "es2018",
|
|
5
|
+
"sourceMap": true,
|
|
6
|
+
"strict": false,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"rootDir": ".",
|
|
11
|
+
"outDir": "dist",
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|