Completed
Push — master ( 576d64...22e707 )
by Sander
01:42 queued 33s
created

_API.updateCredential   C

Complexity

Conditions 8
Paths 24

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
c 1
b 0
f 0
nc 24
nop 3
dl 0
loc 31
rs 5.3846
1
/* global sjcl */
2
3
window.PAPI = (function () {
4
    var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
5
    var encryption_config = {
6
        adata: "",
7
        iter: 1000,
8
        ks: 256,
9
        mode: 'ccm',
10
        ts: 64
11
    };
12
    var _API = {
13
        username: '',
14
        password: '',
15
        host: '',
16
17
        getVaults: function (callback) {
18
            api_request('/api/v2/vaults', 'GET', null, callback);
19
        },
20
        getVault: function (vault_guid, callback) {
21
            api_request('/api/v2/vaults/' + vault_guid, 'GET', null, callback);
22
        },
23
        credentialsSet: function () {
24
            var hostSet = (typeof this.host !== 'undefined');
25
            var usernameSet = (this.username !== 'undefined');
26
            var passwordSet = (typeof this.password !== 'undefined');
27
            return (hostSet && usernameSet && passwordSet);
28
        },
29
        decryptString: function (ciphertext, _key) {
30
            ciphertext = window.atob(ciphertext);
31
            var rp = {};
32
            try {
33
                /** global: sjcl */
34
                return sjcl.decrypt(_key, ciphertext, encryption_config, rp);
35
            } catch (e) {
36
                throw e;
37
            }
38
        },
39
        decryptCredential: function (credential, key) {
40
            for (var i = 0; i < _encryptedFields.length; i++) {
41
                var field = _encryptedFields[i];
42
                var fieldValue = credential[field];
43
                var field_decrypted_value;
44
                try {
45
                    field_decrypted_value = this.decryptString(fieldValue, key);
46
                } catch (e) {
47
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
48
                    throw e;
49
                }
50
                try {
51
                    credential[field] = JSON.parse(field_decrypted_value);
52
                } catch (e) {
53
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
54
                }
55
56
            }
57
            return credential;
58
59
        },
60
        encryptString: function (string, _key) {
61
            var rp = {};
62
            /** global: sjcl */
63
            var ct = sjcl.encrypt(_key, string, encryption_config, rp);
64
            return window.btoa(ct);
65
        },
66
        newCredential: function () {
67
            return {
68
                'credential_id': null,
69
                'guid': null,
70
                'vault_id': null,
71
                'label': null,
72
                'description': null,
73
                'created': null,
74
                'changed': null,
75
                'tags': [],
76
                'email': null,
77
                'username': null,
78
                'password': null,
79
                'url': null,
80
                'favicon': null,
81
                'renew_interval': null,
82
                'expire_time': 0,
83
                'delete_time': 0,
84
                'files': [],
85
                'custom_fields': [],
86
                'otp': {},
87
                'hidden': false
88
            };
89
        },
90
        encryptCredential: function (credential, _key) {
91
            for (var i = 0; i < _encryptedFields.length; i++) {
92
                var field = _encryptedFields[i];
93
                var fieldValue = credential[field];
94
                credential[field] = this.encryptString(JSON.stringify(fieldValue), _key);
95
            }
96
            return credential;
97
        },
98
        createCredential: function (credential, _key, callback) {
99
            credential = this.encryptCredential(credential, _key);
100
101
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
102
            var _that = this;
103
104
            api_request('/api/v2/credentials', 'POST', credential, function (r) {
105
                credential.credential_id = r.credential_id;
106
                credential.guid = r.guid;
107
                credential = _that.decryptCredential(credential, _key);
108
                callback(credential);
109
            });
110
        },
111
        encryptSharedCredential: function (credential, sharedKey, origKey) {
112
            var _credential = credential;
113
            _credential.shared_key = this.encryptString(sharedKey, origKey);
114
            var encrypted_fields = _encryptedFields;
115
            for (var i = 0; i < encrypted_fields.length; i++) {
116
                var field = encrypted_fields[i];
117
                var fieldValue = credential[field];
118
                _credential[field] = this.encryptString(JSON.stringify(fieldValue), sharedKey);
119
            }
120
            return _credential;
121
        },
122
123
        updateCredential: function (credential, key, callback) {
124
            var origKey = key;
125
            var _credential, _key;
126
            if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
127
                if (credential.shared_key) {
128
                    _key = this.decryptString(credential.shared_key);
129
                }
130
            }
131
132
            if (credential.hasOwnProperty('acl')) {
133
                _key = this.decryptString(credential.acl.shared_key);
134
            }
135
136
            if (_key) {
137
                _credential = this.encryptSharedCredential(credential, _key, origKey);
138
            } else {
139
                _credential = credential;
140
            }
141
            delete _credential.shared_key;
142
            var regex = /(<([^>]+)>)/ig;
143
            if(_credential.description && _credential.description !== "") {
144
                _credential.description = _credential.description.replace(regex, "");
145
            }
146
147
148
            credential = this.encryptCredential(_credential, key);
149
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
150
            api_request('/api/v2/credentials/' + credential.guid, 'PATCH', credential, function () {
151
                callback(credential);
152
            });
153
        }
154
    };
155
156
    var api_request = function (endpoint, method, data, callback) {
157
        var encodedLogin = btoa(_API.username + ":" + _API.password);
158
159
        var headers = new Headers();
0 ignored issues
show
Bug introduced by
The variable Headers seems to be never declared. If this is a global, consider adding a /** global: Headers */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
160
        headers.append('Authorization', 'Basic ' + encodedLogin);
161
        headers.append("Accept", " application/json, text/plain, */*");
162
        var opts = {
163
            method: method,
164
            headers: headers
165
166
        };
167
168
        if(method.toLowerCase() !== 'get'){
169
            headers.append('content-type','application/json;charset=UTF-8');
170
            opts.body = JSON.stringify(data);
171
        }
172
173
        var request = new Request(_API.host + '/index.php/apps/passman' + endpoint, opts);
0 ignored issues
show
Bug introduced by
The variable Request seems to be never declared. If this is a global, consider adding a /** global: Request */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
174
175
        fetch(request).then(function(response){
176
            if(response.status !== 200){
177
                callback({error: true, result: {statusText: response.statusText, status: response.status}});
178
                return;
179
            }
180
181
            var contentType = response.headers.get("content-type");
182
            if(contentType && contentType.indexOf("application/json") !== -1) {
183
                return response.json().then(function(json) {
184
                    if(json){
185
                        callback(json);
186
                    } else {
187
                        callback({error: true, result: {statusText: 'Empty reply from server', status: 0}});
188
                    }
189
190
                });
191
            } else {
192
                callback({error: true, result: {statusText: 'Invalid reply from server', status: 0}});
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
193
            }
194
195
        }).catch(function (e) {
196
            API.notifications.create('Error', 'Error connecting to server');
197
            callback({error: true, result: {statusText: e, status: 0}});
198
        });
199
    };
200
201
    return _API;
202
}());