@lockerpm/desktop-service 1.0.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/README.md +98 -0
- package/lib/cjs/abstractions/api.service.js +2 -0
- package/lib/cjs/abstractions/crypto.service.js +147 -0
- package/lib/cjs/abstractions/errors.js +99 -0
- package/lib/cjs/abstractions/event.service.js +2 -0
- package/lib/cjs/abstractions/index.js +2 -0
- package/lib/cjs/abstractions/socket.service.js +11 -0
- package/lib/cjs/abstractions/storage.service.js +2 -0
- package/lib/cjs/index.js +243 -0
- package/lib/cjs/misc/config.js +15 -0
- package/lib/cjs/misc/utils.js +37 -0
- package/lib/cjs/proto/google/api/annotations.js +2 -0
- package/lib/cjs/proto/google/api/http.js +477 -0
- package/lib/cjs/proto/google/protobuf/descriptor.js +4873 -0
- package/lib/cjs/proto/locker-service-grpc.js +1915 -0
- package/lib/cjs/services/api.service.js +182 -0
- package/lib/cjs/services/cache.service.js +50 -0
- package/lib/cjs/services/core-crypto.service.js +193 -0
- package/lib/cjs/services/crypto.service.js +101 -0
- package/lib/cjs/services/event.service.js +31 -0
- package/lib/cjs/services/fido.service.js +136 -0
- package/lib/cjs/services/grpc.service.js +130 -0
- package/lib/cjs/services/log.service.js +30 -0
- package/lib/cjs/services/pairing.service.js +122 -0
- package/lib/cjs/services/socket.service.js +280 -0
- package/lib/cjs/services/user.service.js +134 -0
- package/lib/cjs/types/abstractions/api.service.d.ts +40 -0
- package/lib/cjs/types/abstractions/api.service.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/crypto.service.d.ts +46 -0
- package/lib/cjs/types/abstractions/crypto.service.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/errors.d.ts +73 -0
- package/lib/cjs/types/abstractions/errors.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/event.service.d.ts +23 -0
- package/lib/cjs/types/abstractions/event.service.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/index.d.ts +56 -0
- package/lib/cjs/types/abstractions/index.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/socket.service.d.ts +52 -0
- package/lib/cjs/types/abstractions/socket.service.d.ts.map +1 -0
- package/lib/cjs/types/abstractions/storage.service.d.ts +6 -0
- package/lib/cjs/types/abstractions/storage.service.d.ts.map +1 -0
- package/lib/cjs/types/index.d.ts +164 -0
- package/lib/cjs/types/index.d.ts.map +1 -0
- package/lib/cjs/types/misc/config.d.ts +6 -0
- package/lib/cjs/types/misc/config.d.ts.map +1 -0
- package/lib/cjs/types/misc/utils.d.ts +21 -0
- package/lib/cjs/types/misc/utils.d.ts.map +1 -0
- package/lib/cjs/types/proto/google/api/annotations.d.ts +2 -0
- package/lib/cjs/types/proto/google/api/annotations.d.ts.map +1 -0
- package/lib/cjs/types/proto/google/api/http.d.ts +195 -0
- package/lib/cjs/types/proto/google/api/http.d.ts.map +1 -0
- package/lib/cjs/types/proto/google/protobuf/descriptor.d.ts +3409 -0
- package/lib/cjs/types/proto/google/protobuf/descriptor.d.ts.map +1 -0
- package/lib/cjs/types/proto/locker-service-grpc.d.ts +622 -0
- package/lib/cjs/types/proto/locker-service-grpc.d.ts.map +1 -0
- package/lib/cjs/types/services/api.service.d.ts +37 -0
- package/lib/cjs/types/services/api.service.d.ts.map +1 -0
- package/lib/cjs/types/services/cache.service.d.ts +10 -0
- package/lib/cjs/types/services/cache.service.d.ts.map +1 -0
- package/lib/cjs/types/services/core-crypto.service.d.ts +17 -0
- package/lib/cjs/types/services/core-crypto.service.d.ts.map +1 -0
- package/lib/cjs/types/services/crypto.service.d.ts +23 -0
- package/lib/cjs/types/services/crypto.service.d.ts.map +1 -0
- package/lib/cjs/types/services/event.service.d.ts +14 -0
- package/lib/cjs/types/services/event.service.d.ts.map +1 -0
- package/lib/cjs/types/services/fido.service.d.ts +40 -0
- package/lib/cjs/types/services/fido.service.d.ts.map +1 -0
- package/lib/cjs/types/services/grpc.service.d.ts +34 -0
- package/lib/cjs/types/services/grpc.service.d.ts.map +1 -0
- package/lib/cjs/types/services/log.service.d.ts +13 -0
- package/lib/cjs/types/services/log.service.d.ts.map +1 -0
- package/lib/cjs/types/services/pairing.service.d.ts +37 -0
- package/lib/cjs/types/services/pairing.service.d.ts.map +1 -0
- package/lib/cjs/types/services/socket.service.d.ts +39 -0
- package/lib/cjs/types/services/socket.service.d.ts.map +1 -0
- package/lib/cjs/types/services/user.service.d.ts +32 -0
- package/lib/cjs/types/services/user.service.d.ts.map +1 -0
- package/lib/cjs/types/usecases/fido.d.ts +54 -0
- package/lib/cjs/types/usecases/fido.d.ts.map +1 -0
- package/lib/cjs/usecases/fido.js +227 -0
- package/lib/esm/abstractions/api.service.js +2 -0
- package/lib/esm/abstractions/crypto.service.js +165 -0
- package/lib/esm/abstractions/errors.js +100 -0
- package/lib/esm/abstractions/event.service.js +2 -0
- package/lib/esm/abstractions/index.js +2 -0
- package/lib/esm/abstractions/socket.service.js +11 -0
- package/lib/esm/abstractions/storage.service.js +2 -0
- package/lib/esm/index.mjs +227 -0
- package/lib/esm/misc/config.js +15 -0
- package/lib/esm/misc/utils.js +37 -0
- package/lib/esm/proto/google/api/annotations.js +2 -0
- package/lib/esm/proto/google/api/http.js +468 -0
- package/lib/esm/proto/google/protobuf/descriptor.js +4830 -0
- package/lib/esm/proto/locker-service-grpc.js +1892 -0
- package/lib/esm/services/api.service.js +177 -0
- package/lib/esm/services/cache.service.js +52 -0
- package/lib/esm/services/core-crypto.service.js +164 -0
- package/lib/esm/services/crypto.service.js +83 -0
- package/lib/esm/services/event.service.js +33 -0
- package/lib/esm/services/fido.service.js +139 -0
- package/lib/esm/services/grpc.service.js +119 -0
- package/lib/esm/services/log.service.js +31 -0
- package/lib/esm/services/pairing.service.js +107 -0
- package/lib/esm/services/socket.service.js +265 -0
- package/lib/esm/services/user.service.js +116 -0
- package/lib/esm/types/abstractions/api.service.d.ts +40 -0
- package/lib/esm/types/abstractions/api.service.d.ts.map +1 -0
- package/lib/esm/types/abstractions/crypto.service.d.ts +46 -0
- package/lib/esm/types/abstractions/crypto.service.d.ts.map +1 -0
- package/lib/esm/types/abstractions/errors.d.ts +73 -0
- package/lib/esm/types/abstractions/errors.d.ts.map +1 -0
- package/lib/esm/types/abstractions/event.service.d.ts +23 -0
- package/lib/esm/types/abstractions/event.service.d.ts.map +1 -0
- package/lib/esm/types/abstractions/index.d.ts +56 -0
- package/lib/esm/types/abstractions/index.d.ts.map +1 -0
- package/lib/esm/types/abstractions/socket.service.d.ts +52 -0
- package/lib/esm/types/abstractions/socket.service.d.ts.map +1 -0
- package/lib/esm/types/abstractions/storage.service.d.ts +6 -0
- package/lib/esm/types/abstractions/storage.service.d.ts.map +1 -0
- package/lib/esm/types/index.d.ts +164 -0
- package/lib/esm/types/index.d.ts.map +1 -0
- package/lib/esm/types/misc/config.d.ts +6 -0
- package/lib/esm/types/misc/config.d.ts.map +1 -0
- package/lib/esm/types/misc/utils.d.ts +21 -0
- package/lib/esm/types/misc/utils.d.ts.map +1 -0
- package/lib/esm/types/proto/google/api/annotations.d.ts +2 -0
- package/lib/esm/types/proto/google/api/annotations.d.ts.map +1 -0
- package/lib/esm/types/proto/google/api/http.d.ts +195 -0
- package/lib/esm/types/proto/google/api/http.d.ts.map +1 -0
- package/lib/esm/types/proto/google/protobuf/descriptor.d.ts +3409 -0
- package/lib/esm/types/proto/google/protobuf/descriptor.d.ts.map +1 -0
- package/lib/esm/types/proto/locker-service-grpc.d.ts +622 -0
- package/lib/esm/types/proto/locker-service-grpc.d.ts.map +1 -0
- package/lib/esm/types/services/api.service.d.ts +37 -0
- package/lib/esm/types/services/api.service.d.ts.map +1 -0
- package/lib/esm/types/services/cache.service.d.ts +10 -0
- package/lib/esm/types/services/cache.service.d.ts.map +1 -0
- package/lib/esm/types/services/core-crypto.service.d.ts +17 -0
- package/lib/esm/types/services/core-crypto.service.d.ts.map +1 -0
- package/lib/esm/types/services/crypto.service.d.ts +23 -0
- package/lib/esm/types/services/crypto.service.d.ts.map +1 -0
- package/lib/esm/types/services/event.service.d.ts +14 -0
- package/lib/esm/types/services/event.service.d.ts.map +1 -0
- package/lib/esm/types/services/fido.service.d.ts +40 -0
- package/lib/esm/types/services/fido.service.d.ts.map +1 -0
- package/lib/esm/types/services/grpc.service.d.ts +34 -0
- package/lib/esm/types/services/grpc.service.d.ts.map +1 -0
- package/lib/esm/types/services/log.service.d.ts +13 -0
- package/lib/esm/types/services/log.service.d.ts.map +1 -0
- package/lib/esm/types/services/pairing.service.d.ts +37 -0
- package/lib/esm/types/services/pairing.service.d.ts.map +1 -0
- package/lib/esm/types/services/socket.service.d.ts +39 -0
- package/lib/esm/types/services/socket.service.d.ts.map +1 -0
- package/lib/esm/types/services/user.service.d.ts +32 -0
- package/lib/esm/types/services/user.service.d.ts.map +1 -0
- package/lib/esm/types/usecases/fido.d.ts +54 -0
- package/lib/esm/types/usecases/fido.d.ts.map +1 -0
- package/lib/esm/usecases/fido.js +201 -0
- package/package.json +55 -0
|
@@ -0,0 +1,177 @@
|
|
|
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.ApiService = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const errors_1 = require("../abstractions/errors");
|
|
9
|
+
class ApiService {
|
|
10
|
+
baseUrl;
|
|
11
|
+
token;
|
|
12
|
+
headers;
|
|
13
|
+
logger;
|
|
14
|
+
constructor(params) {
|
|
15
|
+
const { baseUrl, logger, headers } = params;
|
|
16
|
+
this.baseUrl = baseUrl;
|
|
17
|
+
this.token = '';
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.headers = headers || {};
|
|
20
|
+
}
|
|
21
|
+
setToken(token) {
|
|
22
|
+
this.token = token;
|
|
23
|
+
}
|
|
24
|
+
async getPasswordlessCredentials(email) {
|
|
25
|
+
try {
|
|
26
|
+
const url = `${this.baseUrl}/cystack_platform/pm/passwordless/credential`;
|
|
27
|
+
const res = await axios_1.default.get(url, {
|
|
28
|
+
params: {
|
|
29
|
+
email,
|
|
30
|
+
},
|
|
31
|
+
headers: this.headers,
|
|
32
|
+
});
|
|
33
|
+
const data = res.data;
|
|
34
|
+
this.logDebug({ url, method: 'GET', data });
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.response?.status === 404) {
|
|
39
|
+
throw new errors_1.ServiceError('1002', error);
|
|
40
|
+
}
|
|
41
|
+
throw new errors_1.ServiceError('1000', error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// TODO: if service is only built by CyStack, then this base API must be fixed
|
|
45
|
+
async getReleases(os) {
|
|
46
|
+
try {
|
|
47
|
+
const url = `${this.baseUrl}/cystack_platform/pm/releases`;
|
|
48
|
+
const res = await axios_1.default.get(url, {
|
|
49
|
+
params: {
|
|
50
|
+
client_id: 'desktop',
|
|
51
|
+
os,
|
|
52
|
+
},
|
|
53
|
+
headers: this.headers,
|
|
54
|
+
});
|
|
55
|
+
const data = res.data;
|
|
56
|
+
this.logDebug({ url, method: 'GET', data });
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
throw new errors_1.ServiceError('1000', error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async setPasswordlessCredential(params) {
|
|
64
|
+
if (!this.token) {
|
|
65
|
+
throw new errors_1.ServiceError('1001');
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const { credentialId, name, type, random } = params;
|
|
69
|
+
const url = `${this.baseUrl}/cystack_platform/pm/passwordless/credential`;
|
|
70
|
+
const res = await axios_1.default.post(url, {
|
|
71
|
+
credential_id: credentialId,
|
|
72
|
+
name,
|
|
73
|
+
type,
|
|
74
|
+
random,
|
|
75
|
+
}, {
|
|
76
|
+
headers: {
|
|
77
|
+
Authorization: `Bearer ${this.token}`,
|
|
78
|
+
...this.headers,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
const data = res.data;
|
|
82
|
+
this.logDebug({ url, method: 'POST', data, payload: params });
|
|
83
|
+
return data;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new errors_1.ServiceError('1000', error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async deletePasswordlessCredential() {
|
|
90
|
+
if (!this.token) {
|
|
91
|
+
throw new errors_1.ServiceError('1001');
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const url = `${this.baseUrl}/cystack_platform/pm/passwordless/credential`;
|
|
95
|
+
await axios_1.default.delete(url, {
|
|
96
|
+
headers: {
|
|
97
|
+
Authorization: `Bearer ${this.token}`,
|
|
98
|
+
...this.headers,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
this.logDebug({
|
|
102
|
+
url,
|
|
103
|
+
method: 'DELETE',
|
|
104
|
+
data: undefined,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new errors_1.ServiceError('1000', error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ---------------- BACKUP KEYS ----------------
|
|
112
|
+
async listBackupPasswordlessCredentials() {
|
|
113
|
+
if (!this.token) {
|
|
114
|
+
throw new errors_1.ServiceError('1001');
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const url = `${this.baseUrl}/cystack_platform/pm/users/backup_credentials`;
|
|
118
|
+
const res = await axios_1.default.get(url, {
|
|
119
|
+
params: {
|
|
120
|
+
paging: 0,
|
|
121
|
+
},
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: `Bearer ${this.token}`,
|
|
124
|
+
...this.headers,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
const data = res.data;
|
|
128
|
+
this.logDebug({ url, method: 'GET', data });
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw new errors_1.ServiceError('1000', error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async setBackupPasswordlessCredential(payload) {
|
|
136
|
+
if (!this.token) {
|
|
137
|
+
throw new errors_1.ServiceError('1001');
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const url = `${this.baseUrl}/cystack_platform/pm/users/backup_credentials`;
|
|
141
|
+
const res = await axios_1.default.post(url, payload, {
|
|
142
|
+
headers: {
|
|
143
|
+
Authorization: `Bearer ${this.token}`,
|
|
144
|
+
...this.headers,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
this.logDebug({ url, method: 'POST', data: res.data, payload });
|
|
148
|
+
return res.data;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw new errors_1.ServiceError('1000', error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async deleteBackupPasswordlessCredential(id) {
|
|
155
|
+
if (!this.token) {
|
|
156
|
+
throw new errors_1.ServiceError('1001');
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const url = `${this.baseUrl}/cystack_platform/pm/users/backup_credentials/${id}`;
|
|
160
|
+
await axios_1.default.delete(url, {
|
|
161
|
+
headers: {
|
|
162
|
+
Authorization: `Bearer ${this.token}`,
|
|
163
|
+
...this.headers,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
throw new errors_1.ServiceError('1000', error);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ---------------- PRIVATE METHODS ----------------
|
|
172
|
+
logDebug(params) {
|
|
173
|
+
const { url, method, data, payload } = params;
|
|
174
|
+
this.logger.debug(`API call ${method} ${url}\nwith ${JSON.stringify(payload)} \nreturn ${JSON.stringify(data)}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.ApiService = ApiService;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CacheService = void 0;
|
|
4
|
+
const locker_service_grpc_1 = require("../proto/locker-service-grpc");
|
|
5
|
+
const errors_1 = require("../abstractions/errors");
|
|
6
|
+
var CacheMessage;
|
|
7
|
+
(function (CacheMessage) {
|
|
8
|
+
CacheMessage["GET_CACHE"] = "getCache";
|
|
9
|
+
CacheMessage["SET_CACHE"] = "setCache";
|
|
10
|
+
})(CacheMessage || (CacheMessage = {}));
|
|
11
|
+
class CacheService {
|
|
12
|
+
logger;
|
|
13
|
+
grpc;
|
|
14
|
+
constructor(logger, grpcService) {
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
this.grpc = grpcService;
|
|
17
|
+
}
|
|
18
|
+
getCache() {
|
|
19
|
+
const req = new locker_service_grpc_1.locker_service_grpc.CacheRequest();
|
|
20
|
+
req.message = CacheMessage.GET_CACHE;
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
this.grpc.client.CacheChannel(req, (err, res) => {
|
|
23
|
+
this.logger.debug(res);
|
|
24
|
+
if (err) {
|
|
25
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!res?.json) {
|
|
29
|
+
resolve(null);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
resolve(JSON.parse(res.json));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
setCache(data) {
|
|
37
|
+
const req = new locker_service_grpc_1.locker_service_grpc.CacheRequest();
|
|
38
|
+
req.message = CacheMessage.SET_CACHE;
|
|
39
|
+
req.json = JSON.stringify(data);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
this.grpc.client.CacheChannel(req, (err, res) => {
|
|
42
|
+
this.logger.debug(res);
|
|
43
|
+
if (err) {
|
|
44
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
resolve();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.CacheService = CacheService;
|
|
@@ -0,0 +1,164 @@
|
|
|
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.CoreCryptoService = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Crypto core from Locker Vault
|
|
9
|
+
* */
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
const crypto_service_1 = require("../abstractions/crypto.service");
|
|
12
|
+
const utils_1 = require("../misc/utils");
|
|
13
|
+
const crypto = crypto_1.default.webcrypto;
|
|
14
|
+
class CoreCryptoService {
|
|
15
|
+
async makeKey(password, salt, kdf, kdfIterations) {
|
|
16
|
+
let key;
|
|
17
|
+
if (!kdf || kdf === crypto_service_1.KdfType.PBKDF2_SHA256) {
|
|
18
|
+
if (!kdfIterations) {
|
|
19
|
+
kdfIterations = 5000;
|
|
20
|
+
}
|
|
21
|
+
else if (kdfIterations < 5000) {
|
|
22
|
+
throw new Error('PBKDF2 iteration minimum is 5000.');
|
|
23
|
+
}
|
|
24
|
+
key = await this.pbkdf2(password, salt, 'sha256', kdfIterations);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('Unknown Kdf.');
|
|
28
|
+
}
|
|
29
|
+
return new crypto_service_1.SymmetricCryptoKey(key);
|
|
30
|
+
}
|
|
31
|
+
async hashPassword(password, key) {
|
|
32
|
+
if (!password || !key) {
|
|
33
|
+
throw new Error('Invalid parameters.');
|
|
34
|
+
}
|
|
35
|
+
const hash = await this.pbkdf2(key.key, password, 'sha256', 1);
|
|
36
|
+
return utils_1.Utils.fromBufferToB64(hash);
|
|
37
|
+
}
|
|
38
|
+
async remakeEncKey(currentEncKey, key) {
|
|
39
|
+
let encKeyEnc;
|
|
40
|
+
if (key.key.byteLength === 32) {
|
|
41
|
+
const newKey = await this.stretchKey(key);
|
|
42
|
+
encKeyEnc = await this.encrypt(currentEncKey, newKey);
|
|
43
|
+
}
|
|
44
|
+
else if (key.key.byteLength === 64) {
|
|
45
|
+
encKeyEnc = await this.encrypt(currentEncKey, key);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
throw new Error('Invalid key size.');
|
|
49
|
+
}
|
|
50
|
+
return [new crypto_service_1.SymmetricCryptoKey(currentEncKey), encKeyEnc];
|
|
51
|
+
}
|
|
52
|
+
// ---------------- PRIVATE METHODS -------------------
|
|
53
|
+
async pbkdf2(password, salt, algorithm, iterations) {
|
|
54
|
+
const wcLen = algorithm === 'sha256' ? 256 : 512;
|
|
55
|
+
const passwordBuf = this.toBuf(password);
|
|
56
|
+
const saltBuf = this.toBuf(salt);
|
|
57
|
+
const pbkdf2Params = {
|
|
58
|
+
name: 'PBKDF2',
|
|
59
|
+
salt: saltBuf,
|
|
60
|
+
iterations,
|
|
61
|
+
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
|
|
62
|
+
};
|
|
63
|
+
const impKey = await crypto.subtle.importKey('raw', passwordBuf, { name: 'PBKDF2' }, false, ['deriveBits']);
|
|
64
|
+
return await crypto.subtle.deriveBits(pbkdf2Params, impKey, wcLen);
|
|
65
|
+
}
|
|
66
|
+
toBuf(value) {
|
|
67
|
+
let buf;
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
buf = utils_1.Utils.fromUtf8ToArray(value).buffer;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
buf = value;
|
|
73
|
+
}
|
|
74
|
+
return buf;
|
|
75
|
+
}
|
|
76
|
+
toWebCryptoAlgorithm(algorithm) {
|
|
77
|
+
if (algorithm === 'md5') {
|
|
78
|
+
throw new Error('MD5 is not supported in WebCrypto.');
|
|
79
|
+
}
|
|
80
|
+
return algorithm === 'sha1' ? 'SHA-1' : algorithm === 'sha256' ? 'SHA-256' : 'SHA-512';
|
|
81
|
+
}
|
|
82
|
+
async stretchKey(key) {
|
|
83
|
+
const newKey = new Uint8Array(64);
|
|
84
|
+
const encKey = await this.hkdfExpand(key.key, 'enc', 32, 'sha256');
|
|
85
|
+
const macKey = await this.hkdfExpand(key.key, 'mac', 32, 'sha256');
|
|
86
|
+
newKey.set(new Uint8Array(encKey));
|
|
87
|
+
newKey.set(new Uint8Array(macKey), 32);
|
|
88
|
+
return new crypto_service_1.SymmetricCryptoKey(newKey.buffer);
|
|
89
|
+
}
|
|
90
|
+
async hkdfExpand(prk, info, outputByteSize, algorithm) {
|
|
91
|
+
const hashLen = algorithm === 'sha256' ? 32 : 64;
|
|
92
|
+
if (outputByteSize > 255 * hashLen) {
|
|
93
|
+
throw new Error('outputByteSize is too large.');
|
|
94
|
+
}
|
|
95
|
+
const prkArr = new Uint8Array(prk);
|
|
96
|
+
if (prkArr.length < hashLen) {
|
|
97
|
+
throw new Error('prk is too small.');
|
|
98
|
+
}
|
|
99
|
+
const infoBuf = this.toBuf(info);
|
|
100
|
+
const infoArr = new Uint8Array(infoBuf);
|
|
101
|
+
let runningOkmLength = 0;
|
|
102
|
+
let previousT = new Uint8Array(0);
|
|
103
|
+
const n = Math.ceil(outputByteSize / hashLen);
|
|
104
|
+
const okm = new Uint8Array(n * hashLen);
|
|
105
|
+
for (let i = 0; i < n; i++) {
|
|
106
|
+
const t = new Uint8Array(previousT.length + infoArr.length + 1);
|
|
107
|
+
t.set(previousT);
|
|
108
|
+
t.set(infoArr, previousT.length);
|
|
109
|
+
t.set([i + 1], t.length - 1);
|
|
110
|
+
previousT = new Uint8Array(await this.hmac(t.buffer, prk, algorithm));
|
|
111
|
+
okm.set(previousT, runningOkmLength);
|
|
112
|
+
runningOkmLength += previousT.length;
|
|
113
|
+
if (runningOkmLength >= outputByteSize) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return okm.slice(0, outputByteSize).buffer;
|
|
118
|
+
}
|
|
119
|
+
async hmac(value, key, algorithm) {
|
|
120
|
+
const signingAlgorithm = {
|
|
121
|
+
name: 'HMAC',
|
|
122
|
+
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
|
|
123
|
+
};
|
|
124
|
+
const impKey = await crypto.subtle.importKey('raw', key, signingAlgorithm, false, ['sign']);
|
|
125
|
+
return await crypto.subtle.sign(signingAlgorithm, impKey, value);
|
|
126
|
+
}
|
|
127
|
+
async encrypt(plainValue, key) {
|
|
128
|
+
let plainBuf;
|
|
129
|
+
if (typeof plainValue === 'string') {
|
|
130
|
+
plainBuf = utils_1.Utils.fromUtf8ToArray(plainValue).buffer;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
plainBuf = plainValue;
|
|
134
|
+
}
|
|
135
|
+
const encObj = await this.aesEncrypt(plainBuf, key);
|
|
136
|
+
const iv = utils_1.Utils.fromBufferToB64(encObj.iv);
|
|
137
|
+
const data = utils_1.Utils.fromBufferToB64(encObj.data);
|
|
138
|
+
const mac = encObj.mac ? utils_1.Utils.fromBufferToB64(encObj.mac) : undefined;
|
|
139
|
+
return new crypto_service_1.EncString(encObj.key.encType, data, iv, mac);
|
|
140
|
+
}
|
|
141
|
+
async aesEncrypt(data, key) {
|
|
142
|
+
const obj = new crypto_service_1.EncryptedObject();
|
|
143
|
+
obj.key = key;
|
|
144
|
+
obj.iv = this.randomBytes(16);
|
|
145
|
+
obj.data = await this._aesEncrypt(data, obj.iv, obj.key.encKey);
|
|
146
|
+
if (obj.key.macKey != null) {
|
|
147
|
+
const macData = new Uint8Array(obj.iv.byteLength + obj.data.byteLength);
|
|
148
|
+
macData.set(new Uint8Array(obj.iv), 0);
|
|
149
|
+
macData.set(new Uint8Array(obj.data), obj.iv.byteLength);
|
|
150
|
+
obj.mac = await this.hmac(macData.buffer, obj.key.macKey, 'sha256');
|
|
151
|
+
}
|
|
152
|
+
return obj;
|
|
153
|
+
}
|
|
154
|
+
randomBytes(length) {
|
|
155
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
156
|
+
}
|
|
157
|
+
async _aesEncrypt(data, iv, key) {
|
|
158
|
+
const impKey = await crypto.subtle.importKey('raw', key, { name: 'AES-CBC' }, false, [
|
|
159
|
+
'encrypt',
|
|
160
|
+
]);
|
|
161
|
+
return await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, impKey, data);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.CoreCryptoService = CoreCryptoService;
|
|
@@ -0,0 +1,83 @@
|
|
|
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.CryptoService = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const crypto_service_1 = require("../abstractions/crypto.service");
|
|
10
|
+
const utils_1 = require("../misc/utils");
|
|
11
|
+
const core_crypto_service_1 = require("./core-crypto.service");
|
|
12
|
+
const crypto = crypto_1.default.webcrypto;
|
|
13
|
+
class CryptoService {
|
|
14
|
+
core;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.core = new core_crypto_service_1.CoreCryptoService();
|
|
17
|
+
}
|
|
18
|
+
async createECDHKeyPair() {
|
|
19
|
+
const keyPair = await crypto.subtle.generateKey(crypto_service_1.ECDH, true, ['deriveKey', 'deriveBits']);
|
|
20
|
+
const rawPublicKey = await crypto.subtle.exportKey('raw', keyPair.publicKey);
|
|
21
|
+
return {
|
|
22
|
+
publicKey: utils_1.Utils.fromBufferToHex(rawPublicKey),
|
|
23
|
+
privateKey: keyPair.privateKey,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async createEncKey(theirPublicKey, ourPrivateKey) {
|
|
27
|
+
const sharedSecret = await this.createECDHSharedSecret(theirPublicKey, ourPrivateKey);
|
|
28
|
+
const approveCode = new Uint8Array(sharedSecret, 0, 2).join('').padStart(6, '0').substring(0, 6);
|
|
29
|
+
return {
|
|
30
|
+
encKey: utils_1.Utils.fromBufferToHex(sharedSecret),
|
|
31
|
+
approveCode,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async aesEncrypt(data, key) {
|
|
35
|
+
const iv = this.getRandomValues(16);
|
|
36
|
+
const dataBuffer = new TextEncoder().encode(data);
|
|
37
|
+
const cryptoKey = await crypto.subtle.importKey('raw', utils_1.Utils.fromHexToArray(key), crypto_service_1.AES, false, [
|
|
38
|
+
'encrypt',
|
|
39
|
+
]);
|
|
40
|
+
const encrypted = await crypto.subtle.encrypt({
|
|
41
|
+
name: crypto_service_1.AES.name,
|
|
42
|
+
iv,
|
|
43
|
+
}, cryptoKey, dataBuffer);
|
|
44
|
+
return `${utils_1.Utils.fromBufferToHex(iv)}.${utils_1.Utils.fromBufferToHex(encrypted)}`;
|
|
45
|
+
}
|
|
46
|
+
async aesDecrypt(data, key) {
|
|
47
|
+
const cryptoKey = await crypto.subtle.importKey('raw', utils_1.Utils.fromHexToArray(key), crypto_service_1.AES, false, [
|
|
48
|
+
'decrypt',
|
|
49
|
+
]);
|
|
50
|
+
const [iv, encString] = data.split('.');
|
|
51
|
+
const decrypted = await crypto.subtle.decrypt({
|
|
52
|
+
name: crypto_service_1.AES.name,
|
|
53
|
+
iv: utils_1.Utils.fromHexToArray(iv),
|
|
54
|
+
}, cryptoKey, utils_1.Utils.fromHexToArray(encString));
|
|
55
|
+
const decryptedString = new TextDecoder().decode(decrypted);
|
|
56
|
+
return decryptedString;
|
|
57
|
+
}
|
|
58
|
+
getFileChecksum(path) {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
try {
|
|
61
|
+
const file = fs_1.default.readFileSync(path);
|
|
62
|
+
const checksum = crypto_1.default.createHash('sha256').update(file).digest('hex');
|
|
63
|
+
resolve(checksum);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
reject(error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
getRandomValues(length) {
|
|
71
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
72
|
+
}
|
|
73
|
+
// ---------------- PRIVATE METHODS -------------------
|
|
74
|
+
async createECDHSharedSecret(theirPublicKey, ourPrivateKey) {
|
|
75
|
+
const publicKey = await crypto.subtle.importKey('raw', utils_1.Utils.fromHexToArray(theirPublicKey), crypto_service_1.ECDH, false, []);
|
|
76
|
+
const secret = await crypto.subtle.deriveBits({
|
|
77
|
+
name: crypto_service_1.ECDH.name,
|
|
78
|
+
public: publicKey,
|
|
79
|
+
}, ourPrivateKey, 256);
|
|
80
|
+
return secret;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.CryptoService = CryptoService;
|
|
@@ -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
|
+
exports.EventService = void 0;
|
|
7
|
+
const eventemitter3_1 = __importDefault(require("eventemitter3"));
|
|
8
|
+
class EventService {
|
|
9
|
+
events;
|
|
10
|
+
logger;
|
|
11
|
+
constructor(logger) {
|
|
12
|
+
this.events = new eventemitter3_1.default();
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
emit(event, args) {
|
|
16
|
+
this.logger.debug(`Event '${event}' fired`);
|
|
17
|
+
// console.log(`Event '${event}' fired`)
|
|
18
|
+
return this.events.emit(event, args);
|
|
19
|
+
}
|
|
20
|
+
on(event, handler) {
|
|
21
|
+
return this.events.on(event, handler);
|
|
22
|
+
}
|
|
23
|
+
once(event, handler) {
|
|
24
|
+
return this.events.once(event, handler);
|
|
25
|
+
}
|
|
26
|
+
removeListener(event, handler) {
|
|
27
|
+
this.events.removeListener(event, handler);
|
|
28
|
+
}
|
|
29
|
+
removeAllListeners() {
|
|
30
|
+
this.events.removeAllListeners();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.EventService = EventService;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FidoService = void 0;
|
|
4
|
+
const locker_service_grpc_1 = require("../proto/locker-service-grpc");
|
|
5
|
+
const errors_1 = require("../abstractions/errors");
|
|
6
|
+
var FidoMessage;
|
|
7
|
+
(function (FidoMessage) {
|
|
8
|
+
FidoMessage["DEVICE_LIST"] = "deviceListRequest";
|
|
9
|
+
FidoMessage["DEVICE_SELECT"] = "deviceInitializationRequest";
|
|
10
|
+
FidoMessage["LIST_CREDENTIALS"] = "listCredentialRequest";
|
|
11
|
+
FidoMessage["MAKE_CREDENTIAL"] = "createCredentialRequest";
|
|
12
|
+
FidoMessage["DELETE_CREDENTIAL"] = "deleteCredentialRequest";
|
|
13
|
+
FidoMessage["GET_HMAC"] = "hmacRequest";
|
|
14
|
+
})(FidoMessage || (FidoMessage = {}));
|
|
15
|
+
class FidoService {
|
|
16
|
+
logger;
|
|
17
|
+
eventEmitter;
|
|
18
|
+
grpc;
|
|
19
|
+
constructor(logger, eventEmitter, grpcService) {
|
|
20
|
+
this.logger = logger;
|
|
21
|
+
this.eventEmitter = eventEmitter;
|
|
22
|
+
this.grpc = grpcService;
|
|
23
|
+
}
|
|
24
|
+
getDeviceList() {
|
|
25
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
26
|
+
req.message = FidoMessage.DEVICE_LIST;
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
29
|
+
this.logger.debug(res);
|
|
30
|
+
if (err) {
|
|
31
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!res?.device_list) {
|
|
35
|
+
resolve([]);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
resolve(res.device_list.map((d) => ({
|
|
39
|
+
name: d.name,
|
|
40
|
+
path: d.path,
|
|
41
|
+
})));
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
setSelectedDevice(path) {
|
|
46
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
47
|
+
req.message = FidoMessage.DEVICE_SELECT;
|
|
48
|
+
req.device_path = path;
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
51
|
+
this.logger.debug(res);
|
|
52
|
+
if (err) {
|
|
53
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
resolve(!!res?.success);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
listCredentials(params) {
|
|
61
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
62
|
+
req.message = FidoMessage.LIST_CREDENTIALS;
|
|
63
|
+
req.pin = params.pin;
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
66
|
+
this.logger.debug(res);
|
|
67
|
+
if (err) {
|
|
68
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
resolve(res?.credential_list.map((c) => ({
|
|
72
|
+
name: c.user_name,
|
|
73
|
+
displayName: c.user_display_name,
|
|
74
|
+
credentialId: c.credential_id,
|
|
75
|
+
})) || []);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
makeCredential(params) {
|
|
80
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
81
|
+
req.message = FidoMessage.MAKE_CREDENTIAL;
|
|
82
|
+
req.email = params.email;
|
|
83
|
+
req.name = params.name;
|
|
84
|
+
req.pin = params.pin || '';
|
|
85
|
+
this.eventEmitter.emit(params.pin ? 'fidoRequestTouch' : 'fidoRequestFingerprint', undefined);
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
88
|
+
this.logger.debug(res);
|
|
89
|
+
if (err) {
|
|
90
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
resolve({
|
|
94
|
+
credentialId: res?.credential_id,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
deleteCredential(params) {
|
|
100
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
101
|
+
req.message = FidoMessage.DELETE_CREDENTIAL;
|
|
102
|
+
req.credential_id = params.credentialId;
|
|
103
|
+
req.pin = params.pin;
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
106
|
+
this.logger.debug(res);
|
|
107
|
+
if (err) {
|
|
108
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
resolve(true);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
getHmacSecret(params) {
|
|
116
|
+
const req = new locker_service_grpc_1.locker_service_grpc.FidoRequest();
|
|
117
|
+
req.message = FidoMessage.GET_HMAC;
|
|
118
|
+
req.credential_id = params.credentialId;
|
|
119
|
+
req.salt = params.salt;
|
|
120
|
+
req.pin = params.pin || '';
|
|
121
|
+
// UP is disabled when get hmac -> no need to request touch
|
|
122
|
+
if (!params.pin) {
|
|
123
|
+
this.eventEmitter.emit('fidoRequestFingerprint', undefined);
|
|
124
|
+
}
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
this.grpc.client.FidoChannel(req, (err, res) => {
|
|
127
|
+
this.logger.debug(res);
|
|
128
|
+
if (err) {
|
|
129
|
+
reject(errors_1.ServiceError.fromError(err));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
resolve({
|
|
133
|
+
secret: res?.assertion_hmac || '',
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.FidoService = FidoService;
|