core-3nweb-client-lib 0.53.1 → 0.53.3

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.
@@ -82,6 +82,11 @@ declare namespace web3n {
82
82
  * domain in the address.
83
83
  */
84
84
  noServiceRecord?: true;
85
+
86
+ /**
87
+ * malformedRecord flag indicates that 3NWeb service value is malformed.
88
+ */
89
+ malformedRecord?: true;
85
90
  }
86
91
 
87
92
  interface EncryptionException {
@@ -79,7 +79,7 @@ class SignUp {
79
79
  }
80
80
  async setServiceURL(serviceURL) {
81
81
  const url = new URL(serviceURL);
82
- if (url.protocol !== 'https:') {
82
+ if ((url.protocol !== 'https:') && !url.hostname.endsWith('.onion')) {
83
83
  throw new Error("Url protocol must be https.");
84
84
  }
85
85
  this.serviceURL = serviceURL;
@@ -40,6 +40,9 @@ function domainNotFoundExc(address, cause) {
40
40
  function noServiceRecordExc(address) {
41
41
  return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { noServiceRecord: true });
42
42
  }
43
+ function noMalformedRecordExc(address) {
44
+ return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { malformedRecord: true });
45
+ }
43
46
  function noConnectionExc(cause) {
44
47
  return (0, runtime_1.makeRuntimeException)('connect', {
45
48
  connectType: 'dns',
@@ -249,7 +252,7 @@ function makeServiceLocatorInDNS(...resolvers) {
249
252
  }
250
253
  const recValue = extractPair(txtRecords, serviceLabel);
251
254
  if (recValue) {
252
- return postProcessValue(serviceLabel, recValue);
255
+ return postProcessValueFromDNS(serviceLabel, recValue, address);
253
256
  }
254
257
  else {
255
258
  exc !== null && exc !== void 0 ? exc : (exc = noServiceRecordExc(address));
@@ -259,30 +262,38 @@ function makeServiceLocatorInDNS(...resolvers) {
259
262
  }
260
263
  return locateInDNS;
261
264
  }
262
- function postProcessValue(serviceLabel, recordValue) {
265
+ function postProcessValueFromDNS(serviceLabel, recordValue, address) {
263
266
  switch (serviceLabel) {
264
267
  case 'report':
265
268
  return recordValue;
266
269
  default:
267
- return checkAndPrepareURL(recordValue);
270
+ return checkAndPrepareURLfromDNS(recordValue, address);
268
271
  }
269
272
  }
270
- function checkAndPrepareURL(value) {
271
- // XXX insert some value sanity check
272
- return 'https://' + value;
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
+ }
273
282
  }
274
283
  const wellKnownPath = '/.well-known/3nweb.json';
275
284
  async function locateInWellKnown(request, address, serviceLabel) {
276
285
  const host = domainOfAddress(address);
286
+ const protocol = (host.endsWith('.onion') ? 'http' : 'https');
277
287
  try {
278
288
  const reply = await request({
279
289
  method: 'GET',
280
- url: `https://${host}${wellKnownPath}`
290
+ url: `${protocol}://${host}${wellKnownPath}`,
291
+ responseType: 'json'
281
292
  });
282
293
  if (reply.status === 200) {
283
294
  const recValue = reply.data[serviceLabel];
284
295
  if (recValue) {
285
- return postProcessValue(serviceLabel, recValue);
296
+ return recValue;
286
297
  }
287
298
  else {
288
299
  throw noServiceRecordExc(address);
@@ -33,7 +33,7 @@ async function checkServicesStartingFromSignup(srvLocator, client, signupUrl, si
33
33
  }
34
34
  async function checkService(service, userDomain) {
35
35
  progress === null || progress === void 0 ? void 0 : progress({ start: true, service, userDomain });
36
- const check = await checkUserDomainDNS(srvLocator, service, userDomain);
36
+ const check = await checkUserDomainNames(srvLocator, service, userDomain);
37
37
  recordResult(check);
38
38
  if (check.isOk) {
39
39
  await checkFstServiceEndpoint(service, check.serviceUrl);
@@ -125,12 +125,7 @@ async function checkSignup(client, signupURL, signupToken) {
125
125
  };
126
126
  }
127
127
  }
128
- // const srvLocator = makeServiceLocator(
129
- // { resolveTxt: dns.resolveTxt },
130
- // dohAt(`https://cloudflare-dns.com/dns-query`),
131
- // dohAt(`https://dns.google/resolve`)
132
- // );
133
- async function checkUserDomainDNS(srvLocator, service, domain) {
128
+ async function checkUserDomainNames(srvLocator, service, domain) {
134
129
  try {
135
130
  const serviceUrl = await (srvLocator(service, noop))(`u@${domain}`);
136
131
  return {
@@ -23,7 +23,8 @@ exports.getMailerIdInfoFor = getMailerIdInfoFor;
23
23
  const jwkeys_1 = require("../lib-common/jwkeys");
24
24
  const http_1 = require("../lib-common/exceptions/http");
25
25
  async function readJSONLocatedAt(client, url) {
26
- if ((new URL(url)).protocol !== 'https:') {
26
+ const u = new URL(url);
27
+ if (u.protocol !== 'https:' && !u.hostname.endsWith('.onion')) {
27
28
  throw new Error("Url protocol must be https.");
28
29
  }
29
30
  const rep = await client.doBodylessRequest({
@@ -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
- throw new Error("Url protocol must be https.");
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
- opts.url = (isWS ?
199
- `wss${this.serviceURI.substring(5)}${opts.appPath}` : `${this.serviceURI}${opts.appPath}`);
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
- throw new Error("Url protocol must be https.");
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.");
@@ -18,15 +18,18 @@
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.makeRequestFromNode = makeRequestFromNode;
20
20
  const https = require("https");
21
+ const http = require("http");
21
22
  const request_utils_1 = require("../lib-client/request-utils");
22
23
  function makeRequestFromNode(getAgent) {
23
- const nodeRequest = (opts) => https.request(opts);
24
+ const nodeHttpsRequest = (opts) => https.request(opts);
25
+ const nodeHttpRequest = (opts) => http.request(opts);
24
26
  return (opts, reqContentType, reqBody) => {
25
- const httpsOpts = (0, request_utils_1.formHttpsReqOpts)(opts, reqContentType, reqBody);
27
+ const reqOpts = (0, request_utils_1.formHttpsReqOpts)(opts, reqContentType, reqBody);
26
28
  const agent = getAgent === null || getAgent === void 0 ? void 0 : getAgent();
27
29
  if (agent) {
28
- httpsOpts.agent = agent;
30
+ reqOpts.agent = agent;
29
31
  }
30
- return (0, request_utils_1.processRequest)(nodeRequest, httpsOpts, opts, reqBody);
32
+ const requestFn = ((reqOpts.protocol === 'http:') ? nodeHttpRequest : nodeHttpsRequest);
33
+ return (0, request_utils_1.processRequest)(requestFn, reqOpts, opts, reqBody);
31
34
  };
32
35
  }
@@ -1,11 +1,3 @@
1
- import { ConnectionStatus, RequestOpts } from '../lib-client/request-utils';
2
- import { type Envelope, type RawDuplex } from '../lib-common/ipc/generic-ipc';
3
- type Observer<T> = web3n.Observer<T>;
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.openServiceEventsSrcFromNode = openServiceEventsSrcFromNode;
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
- async function openServiceEventsSrcFromNode(req) {
29
- const { url, sessionId } = req;
30
- const rep = await openSocketFromNode(url, sessionId);
31
- if (rep.status !== 200) {
32
- return rep;
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
- if (!url.startsWith('wss://')) {
161
- throw new Error(`Url protocol must be wss`);
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);
@@ -75,7 +75,7 @@ function resolveTxt(domain) {
75
75
  }
76
76
  const { makeLocator, makeNet } = (0, networks_1.wrapNetworkFns)({ regular: {
77
77
  naming: [{ resolveTxt }],
78
- openServiceEventsSource: websocket_from_node_1.openServiceEventsSrcFromNode,
78
+ openServiceEventsSource: (0, websocket_from_node_1.makeServiceEventsSourceFromNode)(),
79
79
  requests: (0, request_from_node_1.makeRequestFromNode)()
80
80
  } });
81
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.openServiceEventsSrcFromNode);
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()}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-3nweb-client-lib",
3
- "version": "0.53.1",
3
+ "version": "0.53.3",
4
4
  "description": "3NWeb client core library, embeddable into different environments",
5
5
  "main": "build/lib-index.js",
6
6
  "types": "build/lib-index.d.ts",