core-3nweb-client-lib 0.53.0 → 0.53.2
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/build/api-defs/web3n.d.ts +5 -0
- package/build/lib-client/networks.d.ts +2 -1
- package/build/lib-client/networks.js +25 -34
- package/build/lib-client/user-with-mid-session.js +11 -3
- package/build/lib-client/user-with-pkl-session.d.ts +1 -1
- package/build/lib-client/user-with-pkl-session.js +3 -1
- package/build/lib-common-on-node/websocket-from-node.d.ts +3 -11
- package/build/lib-common-on-node/websocket-from-node.js +30 -21
- package/build/tests/libs-for-tests/core-runner.js +2 -1
- package/build/tests/libs-for-tests/setups.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NetClient, RequestFn, OpenServiceEventsSource } from './request-utils';
|
|
2
2
|
import { LogError } from './logging/log-to-file';
|
|
3
3
|
export type ServiceTypeDNSLabel = 'mailerid' | 'asmail' | '3nstorage';
|
|
4
|
-
export type
|
|
4
|
+
export type DNSLabel = ServiceTypeDNSLabel | 'report' | 'w3nApp';
|
|
5
|
+
export type ServiceLocatorMaker = (serviceLabel: DNSLabel, logError: LogError) => ServiceLocator;
|
|
5
6
|
export type ServiceLocator = (address: string) => Promise<string>;
|
|
6
7
|
export interface DnsResolver {
|
|
7
8
|
resolveTxt: (hostname: string) => Promise<string[][]>;
|
|
@@ -34,16 +34,15 @@ function domainOfAddress(address) {
|
|
|
34
34
|
return address.substring(indOfAt + 1);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
function checkAndPrepareURL(value) {
|
|
38
|
-
// XXX insert some value sanity check
|
|
39
|
-
return 'https://' + value;
|
|
40
|
-
}
|
|
41
37
|
function domainNotFoundExc(address, cause) {
|
|
42
38
|
return (0, runtime_1.makeRuntimeException)('service-locating', { address, cause }, { domainNotFound: true });
|
|
43
39
|
}
|
|
44
40
|
function noServiceRecordExc(address) {
|
|
45
41
|
return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { noServiceRecord: true });
|
|
46
42
|
}
|
|
43
|
+
function noMalformedRecordExc(address) {
|
|
44
|
+
return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { malformedRecord: true });
|
|
45
|
+
}
|
|
47
46
|
function noConnectionExc(cause) {
|
|
48
47
|
return (0, runtime_1.makeRuntimeException)('connect', {
|
|
49
48
|
connectType: 'dns',
|
|
@@ -94,7 +93,8 @@ const recordsStarts = {
|
|
|
94
93
|
"3nstorage": '3nstorage=',
|
|
95
94
|
asmail: 'asmail=',
|
|
96
95
|
mailerid: 'mailerid=',
|
|
97
|
-
report: 'report='
|
|
96
|
+
report: 'report=',
|
|
97
|
+
w3nApp: 'w3n-app='
|
|
98
98
|
};
|
|
99
99
|
function getRecordAtStartOf(txt) {
|
|
100
100
|
let service = undefined;
|
|
@@ -147,23 +147,6 @@ exports.TIMEOUT = "ETIMEOUT";
|
|
|
147
147
|
// export const LOADIPHLPAPI = "ELOADIPHLPAPI";
|
|
148
148
|
// export const ADDRGETNETWORKPARAMS = "EADDRGETNETWORKPARAMS";
|
|
149
149
|
// export const CANCELLED = "ECANCELLED";
|
|
150
|
-
// XXX
|
|
151
|
-
// - service exist in network.
|
|
152
|
-
// - we go from name to address to service location in a network, and a request function ?
|
|
153
|
-
// Or, should we assume that request function will engage with proper network, based on location,
|
|
154
|
-
// implying that location string should always map to one network: regular | tor | i2p.
|
|
155
|
-
// Implicit rule allows us not to force making request fn here, as well as naming system in one net,
|
|
156
|
-
// pointing to another. bank.xyz can be served by server <key>.onion, and vice versa.
|
|
157
|
-
//
|
|
158
|
-
// - this function, ... doesn't have to change, as DnsResolver is given. May be we should make a more
|
|
159
|
-
// general wrap, that gonna use this for DNS in regular net?
|
|
160
|
-
// - and, we may probably want to make function here as a reusable wrapper around different network request fns.
|
|
161
|
-
// Regular net request, may internally switch into proxy/hidding modes. Other networks provide anonymity,
|
|
162
|
-
// hence, these additional options should stay "inside" regular network request fn.
|
|
163
|
-
//
|
|
164
|
-
// - should we have a reusable wrapper creator here, creating coherent pair of naming and request functions.
|
|
165
|
-
// Cause, if embedding doesn't have explicit implementation for Tor, both initial naming and net-maker functions
|
|
166
|
-
// should be coherent.
|
|
167
150
|
const onionTLD = '.onion';
|
|
168
151
|
const i2pTLD = '.i2p';
|
|
169
152
|
function makeMissingImplementationException(networkType, location) {
|
|
@@ -269,12 +252,7 @@ function makeServiceLocatorInDNS(...resolvers) {
|
|
|
269
252
|
}
|
|
270
253
|
const recValue = extractPair(txtRecords, serviceLabel);
|
|
271
254
|
if (recValue) {
|
|
272
|
-
|
|
273
|
-
return recValue;
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
return checkAndPrepareURL(recValue);
|
|
277
|
-
}
|
|
255
|
+
return postProcessValueFromDNS(serviceLabel, recValue, address);
|
|
278
256
|
}
|
|
279
257
|
else {
|
|
280
258
|
exc !== null && exc !== void 0 ? exc : (exc = noServiceRecordExc(address));
|
|
@@ -284,6 +262,24 @@ function makeServiceLocatorInDNS(...resolvers) {
|
|
|
284
262
|
}
|
|
285
263
|
return locateInDNS;
|
|
286
264
|
}
|
|
265
|
+
function postProcessValueFromDNS(serviceLabel, recordValue, address) {
|
|
266
|
+
switch (serviceLabel) {
|
|
267
|
+
case 'report':
|
|
268
|
+
return recordValue;
|
|
269
|
+
default:
|
|
270
|
+
return checkAndPrepareURLfromDNS(recordValue, address);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function checkAndPrepareURLfromDNS(value, address) {
|
|
274
|
+
value = `https://${value}`;
|
|
275
|
+
try {
|
|
276
|
+
new URL(value);
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
throw noMalformedRecordExc(address);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
287
283
|
const wellKnownPath = '/.well-known/3nweb.json';
|
|
288
284
|
async function locateInWellKnown(request, address, serviceLabel) {
|
|
289
285
|
const host = domainOfAddress(address);
|
|
@@ -295,12 +291,7 @@ async function locateInWellKnown(request, address, serviceLabel) {
|
|
|
295
291
|
if (reply.status === 200) {
|
|
296
292
|
const recValue = reply.data[serviceLabel];
|
|
297
293
|
if (recValue) {
|
|
298
|
-
|
|
299
|
-
return recValue;
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
return checkAndPrepareURL(recValue);
|
|
303
|
-
}
|
|
294
|
+
return recValue;
|
|
304
295
|
}
|
|
305
296
|
else {
|
|
306
297
|
throw noServiceRecordExc(address);
|
|
@@ -29,7 +29,9 @@ class ServiceUser {
|
|
|
29
29
|
set serviceURI(uriString) {
|
|
30
30
|
const u = new URL(uriString);
|
|
31
31
|
if (u.protocol !== 'https:') {
|
|
32
|
-
|
|
32
|
+
if (!u.hostname.endsWith('.onion')) {
|
|
33
|
+
throw new Error("Url protocol must be https.");
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
36
|
if (!u.host) {
|
|
35
37
|
throw new Error("Host name is missing.");
|
|
@@ -195,8 +197,14 @@ class ServiceUser {
|
|
|
195
197
|
prepCallOpts(opts, isWS) {
|
|
196
198
|
opts.sessionId = this.sessionId;
|
|
197
199
|
if (opts.appPath) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
if (isWS) {
|
|
201
|
+
const columnInd = this.serviceURI.indexOf(':');
|
|
202
|
+
const h = this.serviceURI.substring(0, columnInd);
|
|
203
|
+
opts.url = `${(h === 'https') ? 'wss' : 'ws'}${this.serviceURI.substring(columnInd)}${opts.appPath}`;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
opts.url = `${this.serviceURI}${opts.appPath}`;
|
|
207
|
+
}
|
|
200
208
|
}
|
|
201
209
|
else if (!opts.url) {
|
|
202
210
|
throw new Error(`Missing both appPath and ready url in request options.`);
|
|
@@ -24,7 +24,7 @@ export declare abstract class ServiceUser {
|
|
|
24
24
|
sessionId: string | undefined;
|
|
25
25
|
private uri;
|
|
26
26
|
get serviceURI(): string;
|
|
27
|
-
set serviceURI(uriString: string);
|
|
27
|
+
protected set serviceURI(uriString: string);
|
|
28
28
|
private loginUrlPart;
|
|
29
29
|
private logoutUrlEnd;
|
|
30
30
|
private redirectedFrom;
|
|
@@ -30,7 +30,9 @@ class ServiceUser {
|
|
|
30
30
|
set serviceURI(uriString) {
|
|
31
31
|
const u = new URL(uriString);
|
|
32
32
|
if (u.protocol !== 'https:') {
|
|
33
|
-
|
|
33
|
+
if (!u.hostname.endsWith('.onion')) {
|
|
34
|
+
throw new Error("Url protocol must be https.");
|
|
35
|
+
}
|
|
34
36
|
}
|
|
35
37
|
if (!u.host) {
|
|
36
38
|
throw new Error("Host name is missing.");
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export declare function openServiceEventsSrcFromNode(req: RequestOpts): Promise<{
|
|
5
|
-
status: number;
|
|
6
|
-
data: {
|
|
7
|
-
comm: RawDuplex<Envelope>;
|
|
8
|
-
watch: (obs: Observer<ConnectionStatus>) => (() => void);
|
|
9
|
-
};
|
|
10
|
-
}>;
|
|
11
|
-
export {};
|
|
1
|
+
import { OpenServiceEventsSource } from '../lib-client/request-utils';
|
|
2
|
+
import { Agent } from 'https';
|
|
3
|
+
export declare function makeServiceEventsSourceFromNode(getAgent?: () => Agent | undefined): OpenServiceEventsSource;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
19
|
+
exports.makeServiceEventsSourceFromNode = makeServiceEventsSourceFromNode;
|
|
20
20
|
const WebSocket = require("ws");
|
|
21
21
|
const request_utils_1 = require("../lib-client/request-utils");
|
|
22
22
|
const deferred_1 = require("../lib-common/processes/deferred");
|
|
@@ -25,22 +25,24 @@ const https_1 = require("https");
|
|
|
25
25
|
const generic_ipc_1 = require("../lib-common/ipc/generic-ipc");
|
|
26
26
|
const ws_ipc_1 = require("../lib-common/ipc/ws-ipc");
|
|
27
27
|
const rxjs_1 = require("rxjs");
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const { comm, heartbeat } = makeJsonCommPoint(rep.data);
|
|
35
|
-
return {
|
|
36
|
-
status: rep.status,
|
|
37
|
-
data: {
|
|
38
|
-
comm,
|
|
39
|
-
watch: obs => {
|
|
40
|
-
const sub = heartbeat.subscribe(obs);
|
|
41
|
-
return () => sub.unsubscribe();
|
|
42
|
-
}
|
|
28
|
+
function makeServiceEventsSourceFromNode(getAgent) {
|
|
29
|
+
return async function openServiceEventsSrcFromNode(req) {
|
|
30
|
+
const { url, sessionId } = req;
|
|
31
|
+
const rep = await openSocketFromNode(url, sessionId, getAgent);
|
|
32
|
+
if (rep.status !== 200) {
|
|
33
|
+
return rep;
|
|
43
34
|
}
|
|
35
|
+
const { comm, heartbeat } = makeJsonCommPoint(rep.data);
|
|
36
|
+
return {
|
|
37
|
+
status: rep.status,
|
|
38
|
+
data: {
|
|
39
|
+
comm,
|
|
40
|
+
watch: obs => {
|
|
41
|
+
const sub = heartbeat.subscribe(obs);
|
|
42
|
+
return () => sub.unsubscribe();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
const MAX_TXT_BUFFER = 64 * 1024;
|
|
@@ -156,13 +158,12 @@ function makeHeartbeat(url) {
|
|
|
156
158
|
otherBeat
|
|
157
159
|
};
|
|
158
160
|
}
|
|
159
|
-
function openSocketFromNode(url, sessionId) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
161
|
+
function openSocketFromNode(url, sessionId, getAgent) {
|
|
162
|
+
var _a;
|
|
163
|
+
ensureWebSocketUrlOK(url);
|
|
163
164
|
const headers = {};
|
|
164
165
|
headers[request_utils_1.SESSION_ID_HEADER] = sessionId;
|
|
165
|
-
const ws = new WebSocket(url, { headers, agent: https_1.globalAgent });
|
|
166
|
+
const ws = new WebSocket(url, { headers, agent: (_a = getAgent === null || getAgent === void 0 ? void 0 : getAgent()) !== null && _a !== void 0 ? _a : https_1.globalAgent });
|
|
166
167
|
let opening = (0, deferred_1.defer)();
|
|
167
168
|
const initOnError = (err) => {
|
|
168
169
|
opening === null || opening === void 0 ? void 0 : opening.reject((0, http_1.makeConnectionException)(url, undefined, `WebSocket connection error: ${err.message}`));
|
|
@@ -193,4 +194,12 @@ function openSocketFromNode(url, sessionId) {
|
|
|
193
194
|
});
|
|
194
195
|
return opening.promise;
|
|
195
196
|
}
|
|
197
|
+
function ensureWebSocketUrlOK(href) {
|
|
198
|
+
const url = new URL(href);
|
|
199
|
+
if (url.protocol === 'ws:') {
|
|
200
|
+
if (!url.hostname.endsWith('.onion')) {
|
|
201
|
+
throw new Error(`Url protocol must be wss`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
196
205
|
Object.freeze(exports);
|
|
@@ -63,6 +63,7 @@ exports.testApp = {
|
|
|
63
63
|
let numOfRunningCores = 0;
|
|
64
64
|
const DATA_FOLDER = (0, path_1.join)(__dirname, '..', '..', '..', 'test-data');
|
|
65
65
|
function resolveTxt(domain) {
|
|
66
|
+
// used non-promise dns method mocked for test data, hence, we use it here
|
|
66
67
|
return new Promise((resolve, reject) => (0, dns_1.resolveTxt)(domain, (err, records) => {
|
|
67
68
|
if (err) {
|
|
68
69
|
reject(err);
|
|
@@ -74,7 +75,7 @@ function resolveTxt(domain) {
|
|
|
74
75
|
}
|
|
75
76
|
const { makeLocator, makeNet } = (0, networks_1.wrapNetworkFns)({ regular: {
|
|
76
77
|
naming: [{ resolveTxt }],
|
|
77
|
-
openServiceEventsSource: websocket_from_node_1.
|
|
78
|
+
openServiceEventsSource: (0, websocket_from_node_1.makeServiceEventsSourceFromNode)(),
|
|
78
79
|
requests: (0, request_from_node_1.makeRequestFromNode)()
|
|
79
80
|
} });
|
|
80
81
|
class CoreRunner {
|
|
@@ -262,7 +262,7 @@ function domainFromUserId(userId) {
|
|
|
262
262
|
function serviceWithMailerIdLogin() {
|
|
263
263
|
const testSrv = (new URL(SIGNUP_URL)).host;
|
|
264
264
|
const serviceUrl = `https://${testSrv}/asmail/retrieval/login/mailerid`;
|
|
265
|
-
const net = (0, request_utils_1.makeNetClient)((0, request_from_node_1.makeRequestFromNode)(), websocket_from_node_1.
|
|
265
|
+
const net = (0, request_utils_1.makeNetClient)((0, request_from_node_1.makeRequestFromNode)(), (0, websocket_from_node_1.makeServiceEventsSourceFromNode)());
|
|
266
266
|
async function isSessionValid(sessionId) {
|
|
267
267
|
const rep = await net.doBodylessRequest({
|
|
268
268
|
url: `https://${testSrv}/asmail/retrieval/${retrieval_1.listMsgs.genUrlEnd()}`,
|