@binsky/passman-client-ts 0.1.0-7
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/README.md +9 -0
- package/lib/BrowserStorage.d.ts +39 -0
- package/lib/BrowserStorage.js +137 -0
- package/lib/Exception/ConfigurationError.d.ts +6 -0
- package/lib/Exception/ConfigurationError.js +11 -0
- package/lib/Exception/FormFieldError.d.ts +4 -0
- package/lib/Exception/FormFieldError.js +2 -0
- package/lib/Interfaces/Credential/CredentialInterface.d.ts +33 -0
- package/lib/Interfaces/Credential/CredentialInterface.js +2 -0
- package/lib/Interfaces/Credential/CustomFieldInterface.d.ts +6 -0
- package/lib/Interfaces/Credential/CustomFieldInterface.js +2 -0
- package/lib/Interfaces/Credential/EncryptedCredentialInterface.d.ts +31 -0
- package/lib/Interfaces/Credential/EncryptedCredentialInterface.js +2 -0
- package/lib/Interfaces/Credential/IconInterface.d.ts +4 -0
- package/lib/Interfaces/Credential/IconInterface.js +2 -0
- package/lib/Interfaces/Credential/OTPConfigInterface.d.ts +14 -0
- package/lib/Interfaces/Credential/OTPConfigInterface.js +2 -0
- package/lib/Interfaces/Credential/TagInterface.d.ts +3 -0
- package/lib/Interfaces/Credential/TagInterface.js +2 -0
- package/lib/Interfaces/CredentialFilterService/FilterStatsInterface.d.ts +10 -0
- package/lib/Interfaces/CredentialFilterService/FilterStatsInterface.js +2 -0
- package/lib/Interfaces/File/DeleteFilesRequestBodyInterface.d.ts +3 -0
- package/lib/Interfaces/File/DeleteFilesRequestBodyInterface.js +2 -0
- package/lib/Interfaces/File/DeleteFilesResponseInterface.d.ts +4 -0
- package/lib/Interfaces/File/DeleteFilesResponseInterface.js +2 -0
- package/lib/Interfaces/File/FileInterface.d.ts +9 -0
- package/lib/Interfaces/File/FileInterface.js +2 -0
- package/lib/Interfaces/File/FileUploadResponseInterface.d.ts +9 -0
- package/lib/Interfaces/File/FileUploadResponseInterface.js +2 -0
- package/lib/Interfaces/LoggingHandlerInterface.d.ts +9 -0
- package/lib/Interfaces/LoggingHandlerInterface.js +2 -0
- package/lib/Interfaces/NextcloudServer/NextcloudServerInterface.d.ts +6 -0
- package/lib/Interfaces/NextcloudServer/NextcloudServerInterface.js +2 -0
- package/lib/Interfaces/PassmanCrypto/GenerateKeypairResponseInterface.d.ts +5 -0
- package/lib/Interfaces/PassmanCrypto/GenerateKeypairResponseInterface.js +2 -0
- package/lib/Interfaces/PassmanCrypto/PEMRSAKeypairInterface.d.ts +4 -0
- package/lib/Interfaces/PassmanCrypto/PEMRSAKeypairInterface.js +2 -0
- package/lib/Interfaces/PassmanCrypto/RSAKeypairInterface.d.ts +5 -0
- package/lib/Interfaces/PassmanCrypto/RSAKeypairInterface.js +2 -0
- package/lib/Interfaces/PasswordGeneratorService/PasswordGeneratorConfigurationInterface.d.ts +9 -0
- package/lib/Interfaces/PasswordGeneratorService/PasswordGeneratorConfigurationInterface.js +2 -0
- package/lib/Interfaces/ReEncryptionService/ReEncryptionProgressInterface.d.ts +7 -0
- package/lib/Interfaces/ReEncryptionService/ReEncryptionProgressInterface.js +2 -0
- package/lib/Interfaces/ReEncryptionService/ReEncryptionStageProgressInterface.d.ts +5 -0
- package/lib/Interfaces/ReEncryptionService/ReEncryptionStageProgressInterface.js +2 -0
- package/lib/Interfaces/Revision/RevisionInterface.d.ts +8 -0
- package/lib/Interfaces/Revision/RevisionInterface.js +2 -0
- package/lib/Interfaces/ShareService/ACLInterface.d.ts +15 -0
- package/lib/Interfaces/ShareService/ACLInterface.js +2 -0
- package/lib/Interfaces/ShareService/CredentialShareRequestInterface.d.ts +16 -0
- package/lib/Interfaces/ShareService/CredentialShareRequestInterface.js +2 -0
- package/lib/Interfaces/Vault/VaultInterface.d.ts +15 -0
- package/lib/Interfaces/Vault/VaultInterface.js +2 -0
- package/lib/Interfaces/Vault/VaultResponseInterface.d.ts +15 -0
- package/lib/Interfaces/Vault/VaultResponseInterface.js +2 -0
- package/lib/LocalPassmanStore.d.ts +4 -0
- package/lib/LocalPassmanStore.js +14 -0
- package/lib/Model/Credential.d.ts +173 -0
- package/lib/Model/Credential.js +594 -0
- package/lib/Model/File.d.ts +15 -0
- package/lib/Model/File.js +55 -0
- package/lib/Model/NextcloudServer.d.ts +27 -0
- package/lib/Model/NextcloudServer.js +108 -0
- package/lib/Model/Revision.d.ts +21 -0
- package/lib/Model/Revision.js +33 -0
- package/lib/Model/SharingACL.d.ts +28 -0
- package/lib/Model/SharingACL.js +48 -0
- package/lib/Model/Vault.d.ts +38 -0
- package/lib/Model/Vault.js +265 -0
- package/lib/PassmanClient.d.ts +20 -0
- package/lib/PassmanClient.js +80 -0
- package/lib/Service/CredentialFilterService.d.ts +24 -0
- package/lib/Service/CredentialFilterService.js +209 -0
- package/lib/Service/CustomMathsService.d.ts +7 -0
- package/lib/Service/CustomMathsService.js +52 -0
- package/lib/Service/DefaultLoggingService.d.ts +10 -0
- package/lib/Service/DefaultLoggingService.js +27 -0
- package/lib/Service/DownloadService.d.ts +12 -0
- package/lib/Service/DownloadService.js +121 -0
- package/lib/Service/OTPService.d.ts +22 -0
- package/lib/Service/OTPService.js +134 -0
- package/lib/Service/PassmanCrypto.d.ts +10 -0
- package/lib/Service/PassmanCrypto.js +57 -0
- package/lib/Service/PasswordGeneratorService.d.ts +6 -0
- package/lib/Service/PasswordGeneratorService.js +73 -0
- package/lib/Service/ReEncryptionService.d.ts +23 -0
- package/lib/Service/ReEncryptionService.js +318 -0
- package/lib/Service/ShareService.d.ts +15 -0
- package/lib/Service/ShareService.js +56 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ConfigurationError_1 = __importDefault(require("../Exception/ConfigurationError"));
|
|
7
|
+
class NextcloudServer {
|
|
8
|
+
serverData;
|
|
9
|
+
logger;
|
|
10
|
+
constructor(serverData, logger) {
|
|
11
|
+
this.serverData = serverData;
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
if (!serverData.baseUrl.startsWith('https://') && !serverData.baseUrl.startsWith('http://')) {
|
|
14
|
+
this.logger.onThrow(new ConfigurationError_1.default('Base URL (or protocol) is invalid'));
|
|
15
|
+
}
|
|
16
|
+
if (serverData.token.length < 3) {
|
|
17
|
+
this.logger.onThrow(new ConfigurationError_1.default('Password or token is invalid'));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
getBaseUrl() {
|
|
21
|
+
return this.serverData.baseUrl;
|
|
22
|
+
}
|
|
23
|
+
setBaseUrl(value) {
|
|
24
|
+
if (!value.startsWith('https://')) {
|
|
25
|
+
this.logger.onThrow(new ConfigurationError_1.default('Base URL is invalid'));
|
|
26
|
+
}
|
|
27
|
+
return this.serverData.baseUrl = value;
|
|
28
|
+
}
|
|
29
|
+
getUser() {
|
|
30
|
+
return this.serverData.user;
|
|
31
|
+
}
|
|
32
|
+
setUser(value) {
|
|
33
|
+
return this.serverData.user = value;
|
|
34
|
+
}
|
|
35
|
+
getToken() {
|
|
36
|
+
return this.serverData.token;
|
|
37
|
+
}
|
|
38
|
+
setToken(value) {
|
|
39
|
+
return this.serverData.token = value;
|
|
40
|
+
}
|
|
41
|
+
getApiUrl() {
|
|
42
|
+
return `${this.getBaseUrl()}/index.php/apps/passman/api/v2/`;
|
|
43
|
+
}
|
|
44
|
+
getEncodedLogin() {
|
|
45
|
+
return btoa(this.getUser() + ":" + this.getToken());
|
|
46
|
+
}
|
|
47
|
+
get = async (endpoint, errorCallback) => {
|
|
48
|
+
return await fetch(this.getApiUrl() + endpoint, {
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Basic ${this.getEncodedLogin()}`
|
|
51
|
+
}
|
|
52
|
+
}).catch((err) => errorCallback(err));
|
|
53
|
+
};
|
|
54
|
+
getJson = async (endpoint, errorCallback) => {
|
|
55
|
+
const res = await fetch(this.getApiUrl() + endpoint, {
|
|
56
|
+
headers: {
|
|
57
|
+
Accept: 'application/json',
|
|
58
|
+
Authorization: `Basic ${this.getEncodedLogin()}`
|
|
59
|
+
}
|
|
60
|
+
}).catch((err) => errorCallback(err));
|
|
61
|
+
if (!res) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (res.status >= 400) {
|
|
65
|
+
const data = await res.json();
|
|
66
|
+
this.logger.onError(data.message);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
return (await res.json());
|
|
70
|
+
};
|
|
71
|
+
delete = async (endpoint, errorCallback) => {
|
|
72
|
+
return await fetch(this.getApiUrl() + endpoint, {
|
|
73
|
+
method: 'DELETE',
|
|
74
|
+
headers: {
|
|
75
|
+
Authorization: `Basic ${this.getEncodedLogin()}`
|
|
76
|
+
}
|
|
77
|
+
}).catch((err) => errorCallback(err));
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Do a post request.
|
|
81
|
+
*
|
|
82
|
+
* @param endpoint
|
|
83
|
+
* @param data will be converted to a json string
|
|
84
|
+
* @param errorCallback
|
|
85
|
+
* @param method
|
|
86
|
+
*/
|
|
87
|
+
postJson = async (endpoint, data, errorCallback, method = 'POST') => {
|
|
88
|
+
const res = await fetch(this.getApiUrl() + endpoint, {
|
|
89
|
+
method: method,
|
|
90
|
+
headers: {
|
|
91
|
+
Accept: 'application/json',
|
|
92
|
+
Authorization: `Basic ${this.getEncodedLogin()}`,
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(data),
|
|
96
|
+
}).catch((err) => errorCallback(err));
|
|
97
|
+
if (!res) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (res.status >= 400) {
|
|
101
|
+
const data = await res.json();
|
|
102
|
+
this.logger.onError(data.message);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
return (await res.json());
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
exports.default = NextcloudServer;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Credential from "./Credential";
|
|
2
|
+
import NextcloudServer from "./NextcloudServer";
|
|
3
|
+
import type Vault from "./Vault";
|
|
4
|
+
import { EncryptedCredentialInterface } from "../Interfaces/Credential/EncryptedCredentialInterface";
|
|
5
|
+
import { FileUploadResponseInterface } from "../Interfaces/File/FileUploadResponseInterface";
|
|
6
|
+
import { RevisionInterface } from "../Interfaces/Revision/RevisionInterface";
|
|
7
|
+
export default class Revision extends Credential {
|
|
8
|
+
ENCRYPTED_FIELDS: string[];
|
|
9
|
+
static updateRevision(revision: RevisionInterface, server: NextcloudServer): Promise<void | FileUploadResponseInterface>;
|
|
10
|
+
/**
|
|
11
|
+
* Create a revision object based on its encrypted data.
|
|
12
|
+
* @param data
|
|
13
|
+
* @param vault
|
|
14
|
+
* @param server
|
|
15
|
+
*/
|
|
16
|
+
static fromData(data: EncryptedCredentialInterface, vault: Vault, server: NextcloudServer): Promise<Revision>;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a local 100% clone of the current credential.
|
|
19
|
+
*/
|
|
20
|
+
clone(): Revision;
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const Credential_1 = __importDefault(require("./Credential"));
|
|
7
|
+
class Revision extends Credential_1.default {
|
|
8
|
+
ENCRYPTED_FIELDS = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url', 'compromised'];
|
|
9
|
+
static updateRevision(revision, server) {
|
|
10
|
+
const credentialGUID = revision.credential_data.guid;
|
|
11
|
+
revision.credential_data = window.btoa(JSON.stringify(revision.credential_data));
|
|
12
|
+
return server.postJson('/credentials/' + credentialGUID + '/revision/' + revision.revision_id, revision, () => {
|
|
13
|
+
}, 'PATCH');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a revision object based on its encrypted data.
|
|
17
|
+
* @param data
|
|
18
|
+
* @param vault
|
|
19
|
+
* @param server
|
|
20
|
+
*/
|
|
21
|
+
static async fromData(data, vault, server) {
|
|
22
|
+
return new Revision(vault, server, data);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a local 100% clone of the current credential.
|
|
26
|
+
*/
|
|
27
|
+
clone() {
|
|
28
|
+
const newCredential = new Revision(this.vault, this.server, this.encryptedData);
|
|
29
|
+
newCredential.sharedCredentialEncryptionKey = this.sharedCredentialEncryptionKey;
|
|
30
|
+
return newCredential;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.default = Revision;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare class SharingACL {
|
|
2
|
+
private permission;
|
|
3
|
+
constructor(permission: number);
|
|
4
|
+
static readonly permissions: {
|
|
5
|
+
READ: number;
|
|
6
|
+
WRITE: number;
|
|
7
|
+
FILES: number;
|
|
8
|
+
HISTORY: number;
|
|
9
|
+
OWNER: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a user has the given permission/s
|
|
13
|
+
* @param permission
|
|
14
|
+
*/
|
|
15
|
+
hasPermission(permission: any): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Adds a permission to a user, leaving any other permissions intact
|
|
18
|
+
* @param permission
|
|
19
|
+
*/
|
|
20
|
+
addPermission(permission: any): void;
|
|
21
|
+
/**
|
|
22
|
+
* Removes a given permission from the item, leaving any other intact
|
|
23
|
+
* @param permission
|
|
24
|
+
*/
|
|
25
|
+
removePermission(permission: any): void;
|
|
26
|
+
togglePermission(permission: any): void;
|
|
27
|
+
getAccessLevel(): number;
|
|
28
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SharingACL = void 0;
|
|
4
|
+
class SharingACL {
|
|
5
|
+
permission;
|
|
6
|
+
constructor(permission) {
|
|
7
|
+
this.permission = permission;
|
|
8
|
+
}
|
|
9
|
+
static permissions = {
|
|
10
|
+
READ: 0x01,
|
|
11
|
+
WRITE: 0x02,
|
|
12
|
+
FILES: 0x04,
|
|
13
|
+
HISTORY: 0x08,
|
|
14
|
+
OWNER: 0x80,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Checks if a user has the given permission/s
|
|
18
|
+
* @param permission
|
|
19
|
+
*/
|
|
20
|
+
hasPermission(permission) {
|
|
21
|
+
return permission === (this.permission & permission);
|
|
22
|
+
}
|
|
23
|
+
;
|
|
24
|
+
/**
|
|
25
|
+
* Adds a permission to a user, leaving any other permissions intact
|
|
26
|
+
* @param permission
|
|
27
|
+
*/
|
|
28
|
+
addPermission(permission) {
|
|
29
|
+
this.permission = this.permission | permission;
|
|
30
|
+
}
|
|
31
|
+
;
|
|
32
|
+
/**
|
|
33
|
+
* Removes a given permission from the item, leaving any other intact
|
|
34
|
+
* @param permission
|
|
35
|
+
*/
|
|
36
|
+
removePermission(permission) {
|
|
37
|
+
this.permission = this.permission & ~permission;
|
|
38
|
+
}
|
|
39
|
+
;
|
|
40
|
+
togglePermission(permission) {
|
|
41
|
+
this.permission ^= permission;
|
|
42
|
+
}
|
|
43
|
+
;
|
|
44
|
+
getAccessLevel() {
|
|
45
|
+
return this.permission;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.SharingACL = SharingACL;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import NextcloudServer from "./NextcloudServer";
|
|
2
|
+
import Credential from "./Credential";
|
|
3
|
+
import { VaultInterface } from "../Interfaces/Vault/VaultInterface";
|
|
4
|
+
export default class Vault {
|
|
5
|
+
private data;
|
|
6
|
+
private server;
|
|
7
|
+
private _vaultKey;
|
|
8
|
+
constructor(data: VaultInterface, server: NextcloudServer);
|
|
9
|
+
static create(vaultName: string, vaultPassword: string, server: NextcloudServer): Promise<Vault>;
|
|
10
|
+
refresh(): Promise<boolean>;
|
|
11
|
+
update(): Promise<boolean>;
|
|
12
|
+
delete(currentPassword: string): Promise<boolean>;
|
|
13
|
+
lock(): void;
|
|
14
|
+
updateSharingKeys(public_sharing_key: string, private_sharing_key: string): Promise<void>;
|
|
15
|
+
testVaultKey(vaultKey: string): boolean;
|
|
16
|
+
private getChallengingFieldValue;
|
|
17
|
+
private getFirstOwnedCredential;
|
|
18
|
+
getCredentialByGuid(guid: string): Credential | undefined;
|
|
19
|
+
getServer(): NextcloudServer;
|
|
20
|
+
get vaultId(): number | null;
|
|
21
|
+
get vaultKey(): string;
|
|
22
|
+
set vaultKey(value: string);
|
|
23
|
+
get guid(): string;
|
|
24
|
+
get name(): string;
|
|
25
|
+
set name(value: string);
|
|
26
|
+
get created(): number;
|
|
27
|
+
get public_sharing_key(): string;
|
|
28
|
+
get private_sharing_key(): string;
|
|
29
|
+
get sharing_keys_generated(): number;
|
|
30
|
+
set sharing_keys_generated(value: number);
|
|
31
|
+
get last_access(): number;
|
|
32
|
+
get challenge_password(): string;
|
|
33
|
+
get delete_request_pending(): boolean;
|
|
34
|
+
set delete_request_pending(value: boolean);
|
|
35
|
+
get vault_settings(): null;
|
|
36
|
+
set vault_settings(value: null);
|
|
37
|
+
get credentials(): Credential[];
|
|
38
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const Credential_1 = __importDefault(require("./Credential"));
|
|
7
|
+
const PassmanCrypto_1 = require("../Service/PassmanCrypto");
|
|
8
|
+
const ShareService_1 = require("../Service/ShareService");
|
|
9
|
+
const File_1 = require("./File");
|
|
10
|
+
const BrowserStorage_1 = require("../BrowserStorage");
|
|
11
|
+
class Vault {
|
|
12
|
+
data;
|
|
13
|
+
server;
|
|
14
|
+
_vaultKey;
|
|
15
|
+
constructor(data, server) {
|
|
16
|
+
this.data = data;
|
|
17
|
+
this.server = server;
|
|
18
|
+
}
|
|
19
|
+
static async create(vaultName, vaultPassword, server) {
|
|
20
|
+
let vaultResponse = await server.postJson('/vaults', { vault_name: vaultName }, (response) => {
|
|
21
|
+
server.logger.onError(response.message);
|
|
22
|
+
});
|
|
23
|
+
if (vaultResponse) {
|
|
24
|
+
const vault = new Vault(vaultResponse, server);
|
|
25
|
+
vault._vaultKey = vaultPassword;
|
|
26
|
+
await PassmanCrypto_1.PassmanCrypto.generateRSAKeypair(2048).then(async (value) => {
|
|
27
|
+
if (value.keypair) {
|
|
28
|
+
const pemKeyPair = PassmanCrypto_1.PassmanCrypto.rsaKeyPairToPEM(value.keypair);
|
|
29
|
+
await vault.updateSharingKeys(pemKeyPair.publicKey, pemKeyPair.privateKey);
|
|
30
|
+
// todo: create hidden test credential
|
|
31
|
+
let testCredential = new Credential_1.default(vault, server);
|
|
32
|
+
testCredential.label = 'Test key for vault ' + vaultName;
|
|
33
|
+
testCredential.hidden = true;
|
|
34
|
+
testCredential.password = 'lorum ipsum';
|
|
35
|
+
if (await testCredential.save()) {
|
|
36
|
+
// todo: refresh / log in to the new vault
|
|
37
|
+
server.logger.onSuccess('Vault successfully created');
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
server.logger.onError('Failed saving test credential in new vault');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
server.logger.onError('Failed to create a new vault rsa key-pair');
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return vault;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async refresh() {
|
|
51
|
+
let vaultResponse = await this.server.getJson('/vaults/' + this.guid, (response) => {
|
|
52
|
+
this.server.logger.onError(response.message);
|
|
53
|
+
});
|
|
54
|
+
if (vaultResponse) {
|
|
55
|
+
const credentials = [];
|
|
56
|
+
for (const credentialData of vaultResponse.credentials) {
|
|
57
|
+
try {
|
|
58
|
+
credentials.push(await Credential_1.default.fromData(credentialData, this, this.server));
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
this.server.logger.anyError(e);
|
|
62
|
+
this.server.logger.onError('Failed to decrypt credential: ' + credentialData.label);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const credentialsSharedWithUs = await ShareService_1.ShareService.getCredentialsSharedWithUs(this, this.server);
|
|
66
|
+
for (const credential of credentialsSharedWithUs) {
|
|
67
|
+
credentials.push(credential);
|
|
68
|
+
}
|
|
69
|
+
// todo: check if a creation of vault.private_sharing_key for old vaults is required
|
|
70
|
+
this.data = {
|
|
71
|
+
challenge_password: vaultResponse.challenge_password,
|
|
72
|
+
created: vaultResponse.created,
|
|
73
|
+
credentials: credentials,
|
|
74
|
+
delete_request_pending: vaultResponse.delete_request_pending,
|
|
75
|
+
guid: vaultResponse.guid,
|
|
76
|
+
last_access: vaultResponse.last_access,
|
|
77
|
+
name: vaultResponse.name,
|
|
78
|
+
private_sharing_key: vaultResponse.private_sharing_key,
|
|
79
|
+
public_sharing_key: vaultResponse.public_sharing_key,
|
|
80
|
+
sharing_keys_generated: vaultResponse.sharing_keys_generated,
|
|
81
|
+
vault_id: vaultResponse.vault_id,
|
|
82
|
+
vault_settings: vaultResponse.vault_settings,
|
|
83
|
+
};
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
async update() {
|
|
89
|
+
const result = await this.server.postJson('/vaults/' + this.data.guid, {
|
|
90
|
+
guid: this.data.guid,
|
|
91
|
+
vault_id: this.data.vault_id,
|
|
92
|
+
name: this.data.name,
|
|
93
|
+
created: this.data.created,
|
|
94
|
+
public_sharing_key: this.data.public_sharing_key,
|
|
95
|
+
last_access: this.data.last_access,
|
|
96
|
+
delete_request_pending: this.data.delete_request_pending,
|
|
97
|
+
sharing_keys_generated: this.data.sharing_keys_generated,
|
|
98
|
+
vault_settings: this.data.vault_settings
|
|
99
|
+
}, (response) => {
|
|
100
|
+
this.server.logger.onError(response.message);
|
|
101
|
+
}, 'PATCH');
|
|
102
|
+
return result === null;
|
|
103
|
+
}
|
|
104
|
+
async delete(currentPassword) {
|
|
105
|
+
if (!this.testVaultKey(currentPassword)) {
|
|
106
|
+
this.server.logger.onError('Invalid password!');
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
let fileIds = [];
|
|
110
|
+
for (const credential of this.credentials) {
|
|
111
|
+
for (const file of credential.files) {
|
|
112
|
+
if (file.file_id) {
|
|
113
|
+
fileIds.push(file.file_id);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const deleteFilesResponse = await File_1.File.deleteFiles({ file_ids: JSON.stringify(fileIds) }, this.server);
|
|
118
|
+
if (!deleteFilesResponse) {
|
|
119
|
+
// void response should "never" happen with a working server side
|
|
120
|
+
this.server.logger.onError('Abort! Failed to request files deletion.');
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
if (!deleteFilesResponse.ok) {
|
|
124
|
+
// minor file deletion issues; continue vault deletion
|
|
125
|
+
this.server.logger.onError('Failed to delete files: ' + deleteFilesResponse.failed.toString());
|
|
126
|
+
}
|
|
127
|
+
let deleteVaultResponse = await this.server.delete('/vaults/' + this.guid, (response) => {
|
|
128
|
+
this.server.logger.onError(response.message);
|
|
129
|
+
});
|
|
130
|
+
if (!deleteVaultResponse) {
|
|
131
|
+
// void response should "never" happen with a working server side
|
|
132
|
+
this.server.logger.onError('Abort! Failed to request vault deletion.');
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (deleteVaultResponse.status === 200) {
|
|
136
|
+
BrowserStorage_1.BrowserStorage.clearAllStorageTypesForVaultGUID(this.guid);
|
|
137
|
+
// todo: delete from local/memory vaults store
|
|
138
|
+
/*let passmanClient = get<PassmanClient>(passmanStore);
|
|
139
|
+
for (let i = 0; i < passmanClient.vaults.length; i++) {
|
|
140
|
+
if (passmanClient.vaults[i].guid === this.guid) {
|
|
141
|
+
passmanClient.vaults.splice(i, 1);
|
|
142
|
+
}
|
|
143
|
+
}*/
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
lock() {
|
|
149
|
+
this.vaultKey = null;
|
|
150
|
+
// clear decrypted credential cache from memory
|
|
151
|
+
for (const credential of this.data.credentials) {
|
|
152
|
+
credential.clearDecryptedDataCache();
|
|
153
|
+
}
|
|
154
|
+
BrowserStorage_1.BrowserStorage.ensureDeleteKeyForAllStorageTypes('vault-' + this.guid, 'vaultKey');
|
|
155
|
+
}
|
|
156
|
+
async updateSharingKeys(public_sharing_key, private_sharing_key) {
|
|
157
|
+
return await this.server.postJson('/vaults/' + this.data.guid + '/sharing-keys', {
|
|
158
|
+
guid: this.data.guid,
|
|
159
|
+
public_sharing_key: public_sharing_key,
|
|
160
|
+
private_sharing_key: PassmanCrypto_1.PassmanCrypto.encryptString(private_sharing_key, this.vaultKey),
|
|
161
|
+
}, (response) => {
|
|
162
|
+
this.server.logger.onError(response.message);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
testVaultKey(vaultKey) {
|
|
166
|
+
try {
|
|
167
|
+
if (this.challenge_password) {
|
|
168
|
+
PassmanCrypto_1.PassmanCrypto.decryptString(this.challenge_password, vaultKey);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
else if (this.credentials.length > 0) {
|
|
172
|
+
PassmanCrypto_1.PassmanCrypto.decryptString(this.getChallengingFieldValue(), vaultKey);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
getChallengingFieldValue() {
|
|
181
|
+
const testCredential = this.getFirstOwnedCredential();
|
|
182
|
+
if (testCredential.getEncrypted().username != null) {
|
|
183
|
+
return testCredential.getEncrypted().username;
|
|
184
|
+
}
|
|
185
|
+
else if (testCredential.getEncrypted().password != null) {
|
|
186
|
+
return testCredential.getEncrypted().password;
|
|
187
|
+
}
|
|
188
|
+
else if (testCredential.getEncrypted().email != null) {
|
|
189
|
+
return testCredential.getEncrypted().email;
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
getFirstOwnedCredential() {
|
|
194
|
+
for (let credential of this.credentials) {
|
|
195
|
+
if (!credential.hasValidSharedKey() && credential.sharedCredentialEncryptionKey === undefined) {
|
|
196
|
+
return credential;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
getCredentialByGuid(guid) {
|
|
201
|
+
for (let credential of this.credentials) {
|
|
202
|
+
if (credential.guid === guid) {
|
|
203
|
+
return credential;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
getServer() {
|
|
208
|
+
return this.server;
|
|
209
|
+
}
|
|
210
|
+
get vaultId() {
|
|
211
|
+
return this.data.vault_id;
|
|
212
|
+
}
|
|
213
|
+
get vaultKey() {
|
|
214
|
+
return this._vaultKey;
|
|
215
|
+
}
|
|
216
|
+
set vaultKey(value) {
|
|
217
|
+
this._vaultKey = value;
|
|
218
|
+
}
|
|
219
|
+
get guid() {
|
|
220
|
+
return this.data.guid;
|
|
221
|
+
}
|
|
222
|
+
get name() {
|
|
223
|
+
return this.data.name;
|
|
224
|
+
}
|
|
225
|
+
set name(value) {
|
|
226
|
+
this.data.name = value;
|
|
227
|
+
}
|
|
228
|
+
get created() {
|
|
229
|
+
return this.data.created;
|
|
230
|
+
}
|
|
231
|
+
get public_sharing_key() {
|
|
232
|
+
return this.data.public_sharing_key;
|
|
233
|
+
}
|
|
234
|
+
get private_sharing_key() {
|
|
235
|
+
return PassmanCrypto_1.PassmanCrypto.decryptString(this.data.private_sharing_key, this.vaultKey);
|
|
236
|
+
}
|
|
237
|
+
get sharing_keys_generated() {
|
|
238
|
+
return this.data.sharing_keys_generated;
|
|
239
|
+
}
|
|
240
|
+
set sharing_keys_generated(value) {
|
|
241
|
+
this.data.sharing_keys_generated = value;
|
|
242
|
+
}
|
|
243
|
+
get last_access() {
|
|
244
|
+
return this.data.last_access;
|
|
245
|
+
}
|
|
246
|
+
get challenge_password() {
|
|
247
|
+
return this.data.challenge_password;
|
|
248
|
+
}
|
|
249
|
+
get delete_request_pending() {
|
|
250
|
+
return this.data.delete_request_pending;
|
|
251
|
+
}
|
|
252
|
+
set delete_request_pending(value) {
|
|
253
|
+
this.data.delete_request_pending = value;
|
|
254
|
+
}
|
|
255
|
+
get vault_settings() {
|
|
256
|
+
return this.data.vault_settings;
|
|
257
|
+
}
|
|
258
|
+
set vault_settings(value) {
|
|
259
|
+
this.data.vault_settings = value;
|
|
260
|
+
}
|
|
261
|
+
get credentials() {
|
|
262
|
+
return this.data.credentials ?? [];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
exports.default = Vault;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import NextcloudServer from "./Model/NextcloudServer";
|
|
2
|
+
import Vault from "./Model/Vault";
|
|
3
|
+
import type { LoggingHandlerInterface } from "./Interfaces/LoggingHandlerInterface";
|
|
4
|
+
import { NextcloudServerInterface } from "./Interfaces/NextcloudServer/NextcloudServerInterface";
|
|
5
|
+
export declare class PassmanClient {
|
|
6
|
+
readonly server: NextcloudServer;
|
|
7
|
+
private logger;
|
|
8
|
+
vaults: Vault[];
|
|
9
|
+
constructor(serverData: NextcloudServerInterface, logger?: LoggingHandlerInterface);
|
|
10
|
+
refreshVaults(throwError?: boolean, preserveInMemoryVaultKeys?: boolean): Promise<boolean>;
|
|
11
|
+
createVault(vaultName: string, vaultPassword: string): Promise<void | Vault>;
|
|
12
|
+
getVaultByGuid(guid: string): Promise<Vault>;
|
|
13
|
+
/**
|
|
14
|
+
* Make sure that this.vaults is an array and not undefined, before using this method.
|
|
15
|
+
* @param guid
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
private _getVaultByGuid;
|
|
19
|
+
getTranslation(lang?: string): Promise<void | object>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PassmanClient = void 0;
|
|
7
|
+
const NextcloudServer_1 = __importDefault(require("./Model/NextcloudServer"));
|
|
8
|
+
const Vault_1 = __importDefault(require("./Model/Vault"));
|
|
9
|
+
const DefaultLoggingService_1 = require("./Service/DefaultLoggingService");
|
|
10
|
+
class PassmanClient {
|
|
11
|
+
server;
|
|
12
|
+
logger;
|
|
13
|
+
vaults;
|
|
14
|
+
constructor(serverData, logger = undefined) {
|
|
15
|
+
this.logger = logger ?? new DefaultLoggingService_1.DefaultLoggingService();
|
|
16
|
+
this.server = new NextcloudServer_1.default(serverData, this.logger);
|
|
17
|
+
}
|
|
18
|
+
async refreshVaults(throwError = false, preserveInMemoryVaultKeys = true) {
|
|
19
|
+
let newVaults = [];
|
|
20
|
+
const vaults = await this.server.getJson('/vaults', (error) => {
|
|
21
|
+
console.error(error);
|
|
22
|
+
if (throwError) {
|
|
23
|
+
this.logger.onThrow(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (vaults) {
|
|
27
|
+
vaults.forEach((vaultData) => {
|
|
28
|
+
const vault = new Vault_1.default(vaultData, this.server);
|
|
29
|
+
if (this.vaults !== undefined && preserveInMemoryVaultKeys) {
|
|
30
|
+
const oldVaultInstance = this._getVaultByGuid(vault.guid);
|
|
31
|
+
if (oldVaultInstance && oldVaultInstance.vaultKey && vault.testVaultKey(oldVaultInstance.vaultKey)) {
|
|
32
|
+
vault.vaultKey = oldVaultInstance.vaultKey;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
newVaults.push(vault);
|
|
36
|
+
});
|
|
37
|
+
this.vaults = newVaults;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
async createVault(vaultName, vaultPassword) {
|
|
43
|
+
let newVault = await Vault_1.default.create(vaultName, vaultPassword, this.server);
|
|
44
|
+
if (newVault) {
|
|
45
|
+
this.vaults.push(newVault);
|
|
46
|
+
return newVault;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async getVaultByGuid(guid) {
|
|
50
|
+
if (this.vaults === undefined) {
|
|
51
|
+
if (!await this.refreshVaults()) {
|
|
52
|
+
this.logger.onError("failed to refresh vaults");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const foundVault = this._getVaultByGuid(guid);
|
|
57
|
+
if (foundVault) {
|
|
58
|
+
return foundVault;
|
|
59
|
+
}
|
|
60
|
+
this.logger.onError(`vault with guid ${guid} not found`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Make sure that this.vaults is an array and not undefined, before using this method.
|
|
64
|
+
* @param guid
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
_getVaultByGuid(guid) {
|
|
68
|
+
for (const element of this.vaults) {
|
|
69
|
+
if (element.guid === guid) {
|
|
70
|
+
return element;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async getTranslation(lang = 'en') {
|
|
75
|
+
return await this.server.getJson('/language?lang=' + lang, (response) => {
|
|
76
|
+
this.logger.onError(response.message);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.PassmanClient = PassmanClient;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type Credential from "../Model/Credential";
|
|
2
|
+
import { FilterStatsInterface } from "../Interfaces/CredentialFilterService/FilterStatsInterface";
|
|
3
|
+
export declare enum FILTERS {
|
|
4
|
+
SHOW_ALL = 0,
|
|
5
|
+
COMPROMISED = 1,
|
|
6
|
+
STRENGTH_LOW = 2,
|
|
7
|
+
STRENGTH_MEDIUM = 3,
|
|
8
|
+
STRENGTH_GOOD = 4,
|
|
9
|
+
EXPIRED = 5,
|
|
10
|
+
DELETED = 6,
|
|
11
|
+
ENCRYPTION_BROKEN = 7
|
|
12
|
+
}
|
|
13
|
+
export declare class CredentialFilterService {
|
|
14
|
+
static getFilteredCredentials: (allCredentials: Credential[], filter: FILTERS, additionalFilterText?: string) => Credential[];
|
|
15
|
+
static getFilterStats: (allCredentials: Credential[]) => FilterStatsInterface;
|
|
16
|
+
static isHidden(credential: Credential): boolean;
|
|
17
|
+
static isDeleted(credential: Credential): boolean;
|
|
18
|
+
static isCompromised(credential: Credential): boolean;
|
|
19
|
+
static isExpired(credential: Credential, now?: number): boolean;
|
|
20
|
+
static hasLowStrength(credential: Credential): boolean;
|
|
21
|
+
static hasMediumStrength(credential: Credential): boolean;
|
|
22
|
+
static hasGoodStrength(credential: Credential): boolean;
|
|
23
|
+
static matchesFilterText(credential: Credential, filterText: string): boolean;
|
|
24
|
+
}
|