core-3nweb-client-lib 0.38.1 → 0.40.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/build/api-defs/asmail.d.ts +0 -16
- package/build/api-defs/startup.d.ts +17 -7
- package/build/api-defs/web3n.d.ts +33 -7
- package/build/core/asmail/inbox/index.js +1 -1
- package/build/core/asmail/sending-params/invitations-anon.js +20 -11
- package/build/core/id-manager/index.js +2 -10
- package/build/core/index.d.ts +3 -4
- package/build/core/index.js +177 -69
- package/build/core/startup/sign-in.d.ts +5 -7
- package/build/core/startup/sign-in.js +41 -54
- package/build/core/startup/sign-up.d.ts +5 -3
- package/build/core/startup/sign-up.js +51 -45
- package/build/core/startup/startup-cap.js +8 -4
- package/build/lib-client/server-events.js +1 -1
- package/build/lib-client/service-locator.js +15 -16
- package/build/lib-common/exceptions/http.d.ts +3 -3
- package/build/lib-common/exceptions/http.js +6 -26
- package/package.json +1 -1
|
@@ -301,22 +301,6 @@ declare namespace web3n.asmail {
|
|
|
301
301
|
msgIsBroken?: true;
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
interface ServLocException extends RuntimeException {
|
|
305
|
-
type: 'service-locating';
|
|
306
|
-
address: string;
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* domainNotFound flag indicates that domain in the address doesn't exist.
|
|
310
|
-
*/
|
|
311
|
-
domainNotFound?: true;
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* noServiceRecord flag indicates that 3NWeb services are not set at
|
|
315
|
-
* domain in the address.
|
|
316
|
-
*/
|
|
317
|
-
noServiceRecord?: true;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
304
|
interface ASMailSendException extends RuntimeException {
|
|
321
305
|
type: 'asmail-delivery';
|
|
322
306
|
address?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright (C) 2016 - 2017, 2020, 2023 3NSoft Inc.
|
|
2
|
+
Copyright (C) 2016 - 2017, 2020, 2023, 2025 3NSoft Inc.
|
|
3
3
|
|
|
4
4
|
This program is free software: you can redistribute it and/or modify it under
|
|
5
5
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -70,9 +70,10 @@ declare namespace web3n.startup {
|
|
|
70
70
|
* @param progressCB is a callback for progress notification
|
|
71
71
|
*/
|
|
72
72
|
createUserParams(
|
|
73
|
-
pass: string,
|
|
74
|
-
progressCB: (progress: number) => void
|
|
73
|
+
pass: string, progressCB: ProgressCB
|
|
75
74
|
): Promise<void>;
|
|
75
|
+
|
|
76
|
+
watchBoot(observer: BootProcessObserver): () => void;
|
|
76
77
|
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -106,8 +107,7 @@ declare namespace web3n.startup {
|
|
|
106
107
|
* @param progressCB is a callback for progress notification
|
|
107
108
|
*/
|
|
108
109
|
completeLoginAndLocalSetup(
|
|
109
|
-
pass: string,
|
|
110
|
-
progressCB: (progress: number) => void
|
|
110
|
+
pass: string, progressCB: ProgressCB
|
|
111
111
|
): Promise<boolean>;
|
|
112
112
|
|
|
113
113
|
/**
|
|
@@ -119,12 +119,22 @@ declare namespace web3n.startup {
|
|
|
119
119
|
* @param progressCB is a callback for progress notification
|
|
120
120
|
*/
|
|
121
121
|
useExistingStorage(
|
|
122
|
-
address: string, pass: string,
|
|
123
|
-
progressCB: (progress: number) => void
|
|
122
|
+
address: string, pass: string, progressCB: ProgressCB
|
|
124
123
|
): Promise<boolean>;
|
|
124
|
+
|
|
125
|
+
watchBoot(observer: BootProcessObserver): () => void;
|
|
125
126
|
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
type ProgressCB = (progress: number) => void;
|
|
130
|
+
type BootProcessObserver = Observer<BootEvent>;
|
|
131
|
+
interface BootEvent {
|
|
132
|
+
coreApp?: string;
|
|
133
|
+
message: string;
|
|
134
|
+
isError?: true;
|
|
135
|
+
isWarning?: true;
|
|
136
|
+
}
|
|
137
|
+
|
|
128
138
|
interface W3N {
|
|
129
139
|
signIn: startup.SignInService;
|
|
130
140
|
signUp: startup.SignUpService;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
declare namespace web3n {
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
interface RuntimeException {
|
|
30
30
|
runtimeException: true;
|
|
31
31
|
type?: string;
|
|
@@ -33,21 +33,47 @@ declare namespace web3n {
|
|
|
33
33
|
message?: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
interface ConnectException extends RuntimeException {
|
|
37
|
+
type: 'connect';
|
|
38
|
+
connectType: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
interface HTTPErrorDetails extends web3n.RuntimeException {
|
|
37
42
|
url: string;
|
|
38
43
|
method: string;
|
|
39
|
-
message?: string;
|
|
40
44
|
}
|
|
41
|
-
|
|
42
|
-
interface
|
|
43
|
-
|
|
45
|
+
|
|
46
|
+
interface HTTPConnectException extends ConnectException {
|
|
47
|
+
connectType: 'http';
|
|
48
|
+
url?: string;
|
|
49
|
+
method?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface DNSConnectException extends ConnectException {
|
|
53
|
+
connectType: 'dns';
|
|
44
54
|
}
|
|
45
|
-
|
|
55
|
+
|
|
46
56
|
interface HTTPException extends HTTPErrorDetails {
|
|
47
57
|
type: 'http-request';
|
|
48
58
|
status: number;
|
|
49
59
|
}
|
|
50
|
-
|
|
60
|
+
|
|
61
|
+
interface ServLocException extends RuntimeException {
|
|
62
|
+
type: 'service-locating';
|
|
63
|
+
address: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* domainNotFound flag indicates that domain in the address doesn't exist.
|
|
67
|
+
*/
|
|
68
|
+
domainNotFound?: true;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* noServiceRecord flag indicates that 3NWeb services are not set at
|
|
72
|
+
* domain in the address.
|
|
73
|
+
*/
|
|
74
|
+
noServiceRecord?: true;
|
|
75
|
+
}
|
|
76
|
+
|
|
51
77
|
interface EncryptionException {
|
|
52
78
|
failedCipherVerification?: true;
|
|
53
79
|
failedSignatureVerification?: true;
|
|
@@ -87,24 +87,33 @@ class AnonymousInvites {
|
|
|
87
87
|
});
|
|
88
88
|
return serverJSON;
|
|
89
89
|
}
|
|
90
|
-
async syncServiceSetting() {
|
|
90
|
+
async syncServiceSetting(rethrowConnectExc = false) {
|
|
91
91
|
// XXX we may have the following bug here:
|
|
92
92
|
// Device with older version of param gets to this point, and sets older
|
|
93
93
|
// value.
|
|
94
94
|
// To protect aginst this case, absorbing from file must ensure highest
|
|
95
95
|
// synced version is read.
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
try {
|
|
97
|
+
const infoOnServer = await this.anonInvitesOnServer.getFromServer()
|
|
98
|
+
.catch((exc) => {
|
|
99
|
+
if (exc.type === 'connect') {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw exc;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const currentVal = this.toServiceJSON();
|
|
107
|
+
if (!(0, json_utils_1.deepEqual)(infoOnServer, currentVal)) {
|
|
108
|
+
await this.anonInvitesOnServer.setOnServer(currentVal);
|
|
100
109
|
}
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
}
|
|
111
|
+
catch (exc) {
|
|
112
|
+
if (!rethrowConnectExc
|
|
113
|
+
&& (exc.type === 'connect')) {
|
|
114
|
+
return;
|
|
103
115
|
}
|
|
104
|
-
|
|
105
|
-
const currentVal = this.toServiceJSON();
|
|
106
|
-
if (!(0, json_utils_1.deepEqual)(infoOnServer, currentVal)) {
|
|
107
|
-
await this.anonInvitesOnServer.setOnServer(currentVal);
|
|
116
|
+
throw exc;
|
|
108
117
|
}
|
|
109
118
|
}
|
|
110
119
|
getAll() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2020 - 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2020 - 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -72,15 +72,7 @@ class IdManager {
|
|
|
72
72
|
}
|
|
73
73
|
static async initFromCachedStore(address, fs, resolver, makeNet, logError, logWarning) {
|
|
74
74
|
const store = key_storage_1.IdKeysStorage.makeWithStorage(fs, logError, logWarning);
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
await idManager.provisionUsingSavedKey();
|
|
78
|
-
return idManager;
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
await logError(err, `Can't initialize id manager from local store`);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
75
|
+
return new IdManager(store, makeNet, resolver, address);
|
|
84
76
|
}
|
|
85
77
|
async startProvisionWithoutSavedKey(address) {
|
|
86
78
|
const midUrl = await this.midServiceFor(address);
|
package/build/core/index.d.ts
CHANGED
|
@@ -20,13 +20,14 @@ export declare class Core {
|
|
|
20
20
|
private asmail;
|
|
21
21
|
private keyrings;
|
|
22
22
|
private idManager;
|
|
23
|
-
private isInitialized;
|
|
24
23
|
private closingProc;
|
|
24
|
+
private isInitialized;
|
|
25
25
|
private constructor();
|
|
26
26
|
static make(conf: CoreConf, makeNet: MakeNet, makeResolver: ServiceLocatorMaker, makeCryptor: makeCryptor): Core;
|
|
27
27
|
start(): {
|
|
28
28
|
capsForStartup: web3n.startup.W3N;
|
|
29
29
|
coreInit: Promise<string>;
|
|
30
|
+
coreAppsInit: Promise<void>;
|
|
30
31
|
};
|
|
31
32
|
private initForNewUser;
|
|
32
33
|
private initForExistingUserWithoutCache;
|
|
@@ -40,11 +41,9 @@ export declare class Core {
|
|
|
40
41
|
private makeKeyringsCAP;
|
|
41
42
|
private makeLogCAP;
|
|
42
43
|
private makeMailerIdCAP;
|
|
43
|
-
private closeBroadcast;
|
|
44
|
-
close$: import("rxjs").Observable<void>;
|
|
45
44
|
close(): Promise<void>;
|
|
46
45
|
private performDataMigrationsAtInit;
|
|
47
|
-
private
|
|
46
|
+
private initCoreApps;
|
|
48
47
|
getStorages(): FactoryOfFSs;
|
|
49
48
|
}
|
|
50
49
|
export {};
|
package/build/core/index.js
CHANGED
|
@@ -24,13 +24,12 @@ const sign_in_1 = require("./startup/sign-in");
|
|
|
24
24
|
const asmail_1 = require("./asmail");
|
|
25
25
|
const error_1 = require("../lib-common/exceptions/error");
|
|
26
26
|
const json_utils_1 = require("../lib-common/json-utils");
|
|
27
|
-
const rxjs_1 = require("rxjs");
|
|
28
27
|
const log_to_file_1 = require("../lib-client/logging/log-to-file");
|
|
29
|
-
const operators_1 = require("rxjs/operators");
|
|
30
28
|
const app_files_1 = require("./app-files");
|
|
31
29
|
const keyring_1 = require("./keyring");
|
|
32
30
|
const constants_1 = require("./storage/common/constants");
|
|
33
31
|
const config_1 = require("./asmail/config");
|
|
32
|
+
const deferred_1 = require("../lib-common/processes/deferred");
|
|
34
33
|
class Core {
|
|
35
34
|
constructor(makeNet, makeResolver, makeCryptor, appDirs, logger, signUpUrl) {
|
|
36
35
|
this.makeNet = makeNet;
|
|
@@ -39,94 +38,184 @@ class Core {
|
|
|
39
38
|
this.logger = logger;
|
|
40
39
|
this.signUpUrl = signUpUrl;
|
|
41
40
|
this.idManager = undefined;
|
|
42
|
-
this.isInitialized = false;
|
|
43
41
|
this.closingProc = undefined;
|
|
44
|
-
this.
|
|
42
|
+
this.isInitialized = false;
|
|
43
|
+
this.cryptor = makeCryptor(this.logger.logError, this.logger.logWarning);
|
|
44
|
+
this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.appDirs.storagePathFor);
|
|
45
|
+
this.keyrings = new keyring_1.Keyrings(this.cryptor.cryptor.sbox);
|
|
46
|
+
this.asmail = new asmail_1.ASMail(this.cryptor.cryptor.sbox, this.makeNet, this.appDirs.inboxPathFor, this.logger);
|
|
47
|
+
Object.seal(this);
|
|
48
|
+
}
|
|
49
|
+
static make(conf, makeNet, makeResolver, makeCryptor) {
|
|
50
|
+
const dirs = (0, app_files_1.appDirs)(conf.dataDir);
|
|
51
|
+
const logger = (0, log_to_file_1.makeLogger)(dirs.getUtilFS());
|
|
52
|
+
const core = new Core(makeNet, makeResolver, makeCryptor, dirs, logger, conf.signUpUrl);
|
|
53
|
+
return core;
|
|
54
|
+
}
|
|
55
|
+
start() {
|
|
56
|
+
const { promise: midPromise, resolve: midDone } = (0, deferred_1.defer)();
|
|
57
|
+
const { watchBoot, emitBootEvent } = makeForBootEvents();
|
|
58
|
+
const signUp = new sign_up_1.SignUp(this.signUpUrl, this.cryptor.cryptor, this.makeNet, this.appDirs.getUsersOnDisk, user => this.initForNewUser(user, midDone, emitBootEvent), watchBoot, this.logger.logError);
|
|
59
|
+
const signIn = new sign_in_1.SignIn(this.cryptor.cryptor, addr => this.initForExistingUserWithoutCache(addr, midDone, emitBootEvent), (addr, storageKey) => this.initForExistingUserWithCache(addr, storageKey, midDone, emitBootEvent), this.appDirs.getUsersOnDisk, watchBoot, this.logger.logError);
|
|
60
|
+
const capsForStartup = {
|
|
61
|
+
signUp: signUp.exposedService(),
|
|
62
|
+
signIn: signIn.exposedService()
|
|
63
|
+
};
|
|
64
|
+
Object.freeze(capsForStartup);
|
|
65
|
+
const coreInit = midPromise.then(idManager => {
|
|
66
|
+
this.idManager = idManager;
|
|
67
|
+
return this.idManager.getId();
|
|
68
|
+
});
|
|
69
|
+
const coreAppsInit = coreInit.then(async () => {
|
|
70
|
+
// XXX This should be removed, at some point, as there will be no more
|
|
71
|
+
// users with very old data folders.
|
|
72
|
+
await this.performDataMigrationsAtInit();
|
|
73
|
+
await this.initCoreApps(emitBootEvent);
|
|
74
|
+
this.isInitialized = true;
|
|
75
|
+
});
|
|
76
|
+
return { coreInit, coreAppsInit, capsForStartup };
|
|
77
|
+
}
|
|
78
|
+
;
|
|
79
|
+
async initForNewUser(u, done, emitBootEvent) {
|
|
80
|
+
var _a;
|
|
81
|
+
emitBootEvent({
|
|
82
|
+
message: `Initializing system for new user ${u.address}`
|
|
83
|
+
});
|
|
84
|
+
try {
|
|
45
85
|
// 1) init of id manager without setting fs
|
|
46
|
-
const stepTwo = await id_manager_1.IdManager.initWithoutStore(u.address, this.makeResolver('mailerid'),
|
|
86
|
+
const stepTwo = await id_manager_1.IdManager.initWithoutStore(u.address, this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
|
|
47
87
|
if (!stepTwo) {
|
|
48
|
-
|
|
88
|
+
const message = `MailerId server doesn't recognize identity ${u.address}`;
|
|
89
|
+
emitBootEvent({ message, isError: true });
|
|
90
|
+
throw new Error(message);
|
|
49
91
|
}
|
|
92
|
+
emitBootEvent({ message: `✔️ started login to provision MailerId` });
|
|
50
93
|
// 2) complete id manager login, without use of fs
|
|
51
94
|
const idManagerInit = await stepTwo(u.midSKey.default);
|
|
52
95
|
if (!idManagerInit) {
|
|
53
|
-
|
|
96
|
+
const message = `Failed to provision MailerId identity`;
|
|
97
|
+
emitBootEvent({ message, isError: true });
|
|
98
|
+
throw new Error(message);
|
|
54
99
|
}
|
|
100
|
+
emitBootEvent({ message: `✔️ MailerId certificate provisioned` });
|
|
55
101
|
const { idManager, setupManagerStorage } = idManagerInit;
|
|
56
102
|
// 3) initialize all storages
|
|
103
|
+
emitBootEvent({ message: `Setting up main storage for new user` });
|
|
57
104
|
const storesUp = await this.storages.initFreshForNewUser(u.address, idManager.getSigner, u.storeParams, u.storeSKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
|
|
58
105
|
if (!storesUp) {
|
|
59
|
-
|
|
106
|
+
const message = `Main store failed to initialize for new user`;
|
|
107
|
+
emitBootEvent({ message, isError: true });
|
|
108
|
+
throw new Error(message);
|
|
60
109
|
}
|
|
110
|
+
emitBootEvent({ message: `✔️ main storage initialized` });
|
|
61
111
|
// 3) give id manager fs, in which it will record labeled key(s)
|
|
112
|
+
emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `setting up storage` });
|
|
62
113
|
await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME), [u.midSKey.labeled]);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
114
|
+
emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `✔️ storage setup completed` });
|
|
115
|
+
done(idManager);
|
|
116
|
+
}
|
|
117
|
+
catch (exc) {
|
|
118
|
+
if (exc.type === 'connect') {
|
|
119
|
+
emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
|
|
123
|
+
}
|
|
124
|
+
throw exc;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async initForExistingUserWithoutCache(address, done, emitBootEvent) {
|
|
128
|
+
var _a;
|
|
129
|
+
emitBootEvent({
|
|
130
|
+
message: `Initializing system for user ${address}, without local cache on this device`
|
|
131
|
+
});
|
|
132
|
+
try {
|
|
66
133
|
// 1) init of id manager without setting fs
|
|
67
|
-
const stepTwo = await id_manager_1.IdManager.initWithoutStore(address, this.makeResolver('mailerid'),
|
|
134
|
+
const stepTwo = await id_manager_1.IdManager.initWithoutStore(address, this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
|
|
68
135
|
if (!stepTwo) {
|
|
136
|
+
emitBootEvent({
|
|
137
|
+
isError: true, message: `MailerId server doesn't recognize identity ${address}`
|
|
138
|
+
});
|
|
69
139
|
return;
|
|
70
140
|
}
|
|
71
141
|
return async (midLoginKey, storageKey) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
142
|
+
var _a;
|
|
143
|
+
try {
|
|
144
|
+
// 2) complete id manager login, without use of fs
|
|
145
|
+
const idManagerInit = await stepTwo(midLoginKey);
|
|
146
|
+
if (!idManagerInit) {
|
|
147
|
+
emitBootEvent({
|
|
148
|
+
isError: true, message: `password/key is incorrect to provision MailerId certificate`
|
|
149
|
+
});
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
emitBootEvent({ message: `✔️ MailerId certificate provisioned` });
|
|
153
|
+
const { idManager, setupManagerStorage } = idManagerInit;
|
|
154
|
+
// 3) initialize all storages
|
|
155
|
+
emitBootEvent({ message: `Setting up main storage without local cache` });
|
|
156
|
+
const storeDone = await this.storages.initFromRemote(address, idManager.getSigner, storageKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
|
|
157
|
+
if (!storeDone) {
|
|
158
|
+
emitBootEvent({ message: `Main store failed to initialize`, isError: true });
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
emitBootEvent({ message: `✔️ main storage initialized` });
|
|
162
|
+
// 4) complete initialization of id manager
|
|
163
|
+
emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `setting up storage` });
|
|
164
|
+
await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME));
|
|
165
|
+
emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `✔️ storage setup completed` });
|
|
166
|
+
done(idManager);
|
|
167
|
+
return true;
|
|
76
168
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
169
|
+
catch (exc) {
|
|
170
|
+
if (exc.type === 'connect') {
|
|
171
|
+
emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
|
|
175
|
+
}
|
|
176
|
+
throw exc;
|
|
82
177
|
}
|
|
83
|
-
// 4) complete initialization of id manager
|
|
84
|
-
await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME));
|
|
85
|
-
return idManager;
|
|
86
178
|
};
|
|
87
|
-
}
|
|
88
|
-
|
|
179
|
+
}
|
|
180
|
+
catch (exc) {
|
|
181
|
+
if (exc.type === 'connect') {
|
|
182
|
+
emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
|
|
186
|
+
}
|
|
187
|
+
throw exc;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async initForExistingUserWithCache(address, storageKey, done, emitBootEvent) {
|
|
191
|
+
var _a;
|
|
192
|
+
emitBootEvent({
|
|
193
|
+
message: `Initializing system for user ${address}, with local cache on this device`
|
|
194
|
+
});
|
|
195
|
+
try {
|
|
196
|
+
emitBootEvent({ message: `Unlocking data from local cache with provided password/key` });
|
|
89
197
|
const completeStorageInit = await this.storages.startInitFromCache(address, storageKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
|
|
90
198
|
if (!completeStorageInit) {
|
|
91
|
-
|
|
199
|
+
emitBootEvent({
|
|
200
|
+
isError: true, message: `password/key is incorrect to decrypt local caches, or caches are damaged`
|
|
201
|
+
});
|
|
202
|
+
return false;
|
|
92
203
|
}
|
|
93
|
-
|
|
204
|
+
emitBootEvent({ message: `✔️ main storage is opened` });
|
|
205
|
+
const idManager = await id_manager_1.IdManager.initFromCachedStore(address, await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME), this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
|
|
94
206
|
if (!idManager) {
|
|
95
|
-
return;
|
|
207
|
+
return false;
|
|
96
208
|
}
|
|
209
|
+
emitBootEvent({ message: `✔️ MailerId manager is initialized` });
|
|
97
210
|
completeStorageInit(idManager.getSigner);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.asmail = new asmail_1.ASMail(this.cryptor.cryptor.sbox, this.makeNet, this.appDirs.inboxPathFor, this.logger);
|
|
106
|
-
Object.seal(this);
|
|
107
|
-
}
|
|
108
|
-
static make(conf, makeNet, makeResolver, makeCryptor) {
|
|
109
|
-
const dirs = (0, app_files_1.appDirs)(conf.dataDir);
|
|
110
|
-
const logger = (0, log_to_file_1.makeLogger)(dirs.getUtilFS());
|
|
111
|
-
const core = new Core(makeNet, makeResolver, makeCryptor, dirs, logger, conf.signUpUrl);
|
|
112
|
-
return core;
|
|
113
|
-
}
|
|
114
|
-
start() {
|
|
115
|
-
const signUp = new sign_up_1.SignUp(this.signUpUrl, this.cryptor.cryptor, this.makeNet.bind(this), this.appDirs.getUsersOnDisk, this.logger.logError);
|
|
116
|
-
const signIn = new sign_in_1.SignIn(this.cryptor.cryptor, this.initForExistingUserWithoutCache, this.initForExistingUserWithCache, this.appDirs.getUsersOnDisk, this.logger.logError);
|
|
117
|
-
const capsForStartup = {
|
|
118
|
-
signUp: signUp.exposedService(),
|
|
119
|
-
signIn: signIn.exposedService()
|
|
120
|
-
};
|
|
121
|
-
Object.freeze(capsForStartup);
|
|
122
|
-
const initFromSignUp$ = signUp.newUser$
|
|
123
|
-
.pipe((0, operators_1.mergeMap)(this.initForNewUser, 1));
|
|
124
|
-
const initFromSignIn$ = signIn.existingUser$;
|
|
125
|
-
const coreInit = (0, rxjs_1.lastValueFrom)((0, rxjs_1.merge)(initFromSignIn$, initFromSignUp$)
|
|
126
|
-
.pipe((0, operators_1.take)(1), (0, operators_1.mergeMap)(idManager => this.initCore(idManager), 1)));
|
|
127
|
-
return { coreInit, capsForStartup };
|
|
211
|
+
done(idManager);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
catch (exc) {
|
|
215
|
+
emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
|
|
216
|
+
throw exc;
|
|
217
|
+
}
|
|
128
218
|
}
|
|
129
|
-
;
|
|
130
219
|
makeCAPsForApp(appDomain, requestedCAPs) {
|
|
131
220
|
if (!this.isInitialized || this.closingProc) {
|
|
132
221
|
throw new Error(`Core is either not yet initialized, or is already closed.`);
|
|
@@ -203,7 +292,6 @@ class Core {
|
|
|
203
292
|
}
|
|
204
293
|
await this.cryptor.close();
|
|
205
294
|
this.cryptor = undefined;
|
|
206
|
-
this.closeBroadcast.next();
|
|
207
295
|
})();
|
|
208
296
|
}
|
|
209
297
|
await this.closingProc;
|
|
@@ -213,25 +301,26 @@ class Core {
|
|
|
213
301
|
await this.storages.migrateCoreAppDataOnFirstRun('synced', `${constants_1.ASMAIL_APP_NAME}/config/introductory-key.json`, `${constants_1.KEYRINGS_APP_NAME}/introductory-keys/published-on-server.json`);
|
|
214
302
|
await this.storages.migrateCoreAppDataOnFirstRun('synced', `${constants_1.ASMAIL_APP_NAME}/config/anonymous/invites.json`, `${constants_1.ASMAIL_APP_NAME}/sending-params/anonymous-invites.json`);
|
|
215
303
|
}
|
|
216
|
-
async
|
|
304
|
+
async initCoreApps(emitBootEvent) {
|
|
305
|
+
// XXX push events to this.bootProcObserver
|
|
306
|
+
var _a;
|
|
217
307
|
try {
|
|
218
|
-
this.idManager = idManager;
|
|
219
308
|
const address = this.idManager.getId();
|
|
220
309
|
const getSigner = this.idManager.getSigner;
|
|
221
310
|
const asmailServerConfig = new config_1.ConfigOfASMailServer(address, getSigner, this.makeResolver('asmail'), this.makeNet());
|
|
222
|
-
|
|
223
|
-
// users with very old data folders.
|
|
224
|
-
await this.performDataMigrationsAtInit();
|
|
311
|
+
emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `starting initialization` });
|
|
225
312
|
const keyringsSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.KEYRINGS_APP_NAME);
|
|
226
313
|
await this.keyrings.init(keyringsSyncedFS, this.idManager.getSigner, asmailServerConfig.makeParamSetterAndGetter('init-pub-key'));
|
|
314
|
+
emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `✔️ initialized` });
|
|
315
|
+
emitBootEvent({ coreApp: constants_1.ASMAIL_APP_NAME, message: `starting initialization` });
|
|
227
316
|
const inboxSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.ASMAIL_APP_NAME);
|
|
228
317
|
const inboxLocalFS = await this.storages.makeLocalFSForApp(constants_1.ASMAIL_APP_NAME);
|
|
229
318
|
await this.asmail.init(this.idManager.getId(), this.idManager.getSigner, inboxSyncedFS, inboxLocalFS, this.storages.storageGetterForASMail(), this.makeResolver, asmailServerConfig, this.keyrings.forASMail());
|
|
230
|
-
|
|
231
|
-
return this.idManager.getId();
|
|
319
|
+
emitBootEvent({ coreApp: constants_1.ASMAIL_APP_NAME, message: `✔️ initialized` });
|
|
232
320
|
}
|
|
233
321
|
catch (err) {
|
|
234
|
-
|
|
322
|
+
emitBootEvent({ isError: true, message: (_a = err.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(err) });
|
|
323
|
+
throw (0, error_1.errWithCause)(err, 'Failed to initialize core apps');
|
|
235
324
|
}
|
|
236
325
|
}
|
|
237
326
|
getStorages() {
|
|
@@ -241,6 +330,25 @@ class Core {
|
|
|
241
330
|
exports.Core = Core;
|
|
242
331
|
Object.freeze(Core.prototype);
|
|
243
332
|
Object.freeze(Core);
|
|
333
|
+
function makeForBootEvents() {
|
|
334
|
+
let bootProcObserver = undefined;
|
|
335
|
+
return {
|
|
336
|
+
watchBoot(obs) {
|
|
337
|
+
var _a;
|
|
338
|
+
if (bootProcObserver) {
|
|
339
|
+
(_a = bootProcObserver.error) === null || _a === void 0 ? void 0 : _a.call(bootProcObserver, `New observer is added, and it stops the previous one.`);
|
|
340
|
+
}
|
|
341
|
+
bootProcObserver = obs;
|
|
342
|
+
return () => {
|
|
343
|
+
bootProcObserver = undefined;
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
emitBootEvent(ev) {
|
|
347
|
+
var _a;
|
|
348
|
+
(_a = bootProcObserver === null || bootProcObserver === void 0 ? void 0 : bootProcObserver.next) === null || _a === void 0 ? void 0 : _a.call(bootProcObserver, ev);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
244
352
|
function makeStoragePolicy(appDomain, requestedCAPs) {
|
|
245
353
|
if (!requestedCAPs.storage) {
|
|
246
354
|
throw new Error(`Missing storage setting in app's manifest`);
|
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
import type { IdManager } from '../id-manager';
|
|
2
1
|
import { ScryptGenParams } from '../../lib-client/key-derivation';
|
|
3
2
|
import type { GetUsersOnDisk } from '../app-files';
|
|
4
3
|
import { Cryptor } from '../../lib-client/cryptor/cryptor';
|
|
5
4
|
import { LogError } from '../../lib-client/logging/log-to-file';
|
|
6
5
|
export type GenerateKey = (derivParams: ScryptGenParams) => Promise<Uint8Array>;
|
|
7
6
|
export type StartInitWithoutCache = (address: string) => Promise<CompleteInitWithoutCache | undefined>;
|
|
8
|
-
export type CompleteInitWithoutCache = (midLoginKey: GenerateKey, storageKey: GenerateKey) => Promise<
|
|
9
|
-
export type InitWithCache = (address: string, storageKey: GenerateKey) => Promise<
|
|
7
|
+
export type CompleteInitWithoutCache = (midLoginKey: GenerateKey, storageKey: GenerateKey) => Promise<boolean>;
|
|
8
|
+
export type InitWithCache = (address: string, storageKey: GenerateKey) => Promise<boolean>;
|
|
10
9
|
type SignInService = web3n.startup.SignInService;
|
|
10
|
+
type ProgressCB = web3n.startup.ProgressCB;
|
|
11
11
|
export declare class SignIn {
|
|
12
12
|
private cryptor;
|
|
13
13
|
private startInitWithoutCache;
|
|
14
14
|
private initWithCache;
|
|
15
15
|
private getUsersOnDisk;
|
|
16
|
+
private readonly watchBoot;
|
|
16
17
|
private readonly logError;
|
|
17
18
|
private completeInitWithoutCache;
|
|
18
|
-
constructor(cryptor: Cryptor, startInitWithoutCache: StartInitWithoutCache, initWithCache: InitWithCache, getUsersOnDisk: GetUsersOnDisk, logError: LogError);
|
|
19
|
+
constructor(cryptor: Cryptor, startInitWithoutCache: StartInitWithoutCache, initWithCache: InitWithCache, getUsersOnDisk: GetUsersOnDisk, watchBoot: SignInService['watchBoot'], logError: LogError);
|
|
19
20
|
exposedService(): SignInService;
|
|
20
21
|
private startLoginToRemoteStorage;
|
|
21
22
|
private completeLoginAndLocalSetup;
|
|
22
|
-
private readonly doneBroadcast;
|
|
23
|
-
readonly existingUser$: import("rxjs").Observable<IdManager>;
|
|
24
23
|
private useExistingStorage;
|
|
25
24
|
private logAndWrap;
|
|
26
25
|
}
|
|
27
|
-
export type ProgressCB = (p: number) => void;
|
|
28
26
|
export declare function makeKeyGenProgressCB(progressStart: number, progressEnd: number, progressCB: ProgressCB): ProgressCB;
|
|
29
27
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2020, 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -19,75 +19,62 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
exports.SignIn = void 0;
|
|
20
20
|
exports.makeKeyGenProgressCB = makeKeyGenProgressCB;
|
|
21
21
|
const key_derivation_1 = require("../../lib-client/key-derivation");
|
|
22
|
-
const rxjs_1 = require("rxjs");
|
|
23
22
|
const error_1 = require("../../lib-common/exceptions/error");
|
|
24
23
|
class SignIn {
|
|
25
|
-
constructor(cryptor, startInitWithoutCache, initWithCache, getUsersOnDisk, logError) {
|
|
24
|
+
constructor(cryptor, startInitWithoutCache, initWithCache, getUsersOnDisk, watchBoot, logError) {
|
|
26
25
|
this.cryptor = cryptor;
|
|
27
26
|
this.startInitWithoutCache = startInitWithoutCache;
|
|
28
27
|
this.initWithCache = initWithCache;
|
|
29
28
|
this.getUsersOnDisk = getUsersOnDisk;
|
|
29
|
+
this.watchBoot = watchBoot;
|
|
30
30
|
this.logError = logError;
|
|
31
31
|
this.completeInitWithoutCache = undefined;
|
|
32
|
-
this.startLoginToRemoteStorage = async (address) => {
|
|
33
|
-
try {
|
|
34
|
-
this.completeInitWithoutCache = await this.startInitWithoutCache(address);
|
|
35
|
-
return !!this.completeInitWithoutCache;
|
|
36
|
-
}
|
|
37
|
-
catch (err) {
|
|
38
|
-
throw await this.logAndWrap(err, 'Fail to start login to remote storage');
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
this.completeLoginAndLocalSetup = async (pass, progressCB) => {
|
|
42
|
-
if (!this.completeInitWithoutCache) {
|
|
43
|
-
throw new Error(`Call method startLoginToRemoteStorage() before calling this.`);
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
const midKeyProgressCB = makeKeyGenProgressCB(0, 50, progressCB);
|
|
47
|
-
const midKeyGen = async (params) => (await (0, key_derivation_1.deriveMidKeyPair)(this.cryptor, pass, params, midKeyProgressCB)).skey;
|
|
48
|
-
const storeKeyProgressCB = makeKeyGenProgressCB(51, 100, progressCB);
|
|
49
|
-
const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
|
|
50
|
-
const idManager = await this.completeInitWithoutCache(midKeyGen, storeKeyGen);
|
|
51
|
-
if (!idManager) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
this.doneBroadcast.next(idManager);
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
throw await this.logAndWrap(err, 'Fail to initialize from a state without cache');
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
this.doneBroadcast = new rxjs_1.Subject();
|
|
62
|
-
this.existingUser$ = this.doneBroadcast.asObservable();
|
|
63
|
-
this.useExistingStorage = async (user, pass, progressCB) => {
|
|
64
|
-
try {
|
|
65
|
-
const storeKeyProgressCB = makeKeyGenProgressCB(0, 99, progressCB);
|
|
66
|
-
const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
|
|
67
|
-
const idManager = await this.initWithCache(user, storeKeyGen);
|
|
68
|
-
if (idManager) {
|
|
69
|
-
this.doneBroadcast.next(idManager);
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
throw await this.logAndWrap(err, 'Failing to start in a state with cache');
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
32
|
Object.seal(this);
|
|
81
33
|
}
|
|
82
34
|
exposedService() {
|
|
83
35
|
const service = {
|
|
84
|
-
completeLoginAndLocalSetup: this.completeLoginAndLocalSetup,
|
|
36
|
+
completeLoginAndLocalSetup: this.completeLoginAndLocalSetup.bind(this),
|
|
85
37
|
getUsersOnDisk: this.getUsersOnDisk,
|
|
86
|
-
startLoginToRemoteStorage: this.startLoginToRemoteStorage,
|
|
87
|
-
useExistingStorage: this.useExistingStorage
|
|
38
|
+
startLoginToRemoteStorage: this.startLoginToRemoteStorage.bind(this),
|
|
39
|
+
useExistingStorage: this.useExistingStorage.bind(this),
|
|
40
|
+
watchBoot: this.watchBoot
|
|
88
41
|
};
|
|
89
42
|
return Object.freeze(service);
|
|
90
43
|
}
|
|
44
|
+
async startLoginToRemoteStorage(address) {
|
|
45
|
+
try {
|
|
46
|
+
this.completeInitWithoutCache = await this.startInitWithoutCache(address);
|
|
47
|
+
return !!this.completeInitWithoutCache;
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
throw await this.logAndWrap(err, 'Fail to start login to remote storage');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async completeLoginAndLocalSetup(pass, progressCB) {
|
|
54
|
+
if (!this.completeInitWithoutCache) {
|
|
55
|
+
throw new Error(`Call method startLoginToRemoteStorage() before calling this.`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const midKeyProgressCB = makeKeyGenProgressCB(0, 50, progressCB);
|
|
59
|
+
const midKeyGen = async (params) => (await (0, key_derivation_1.deriveMidKeyPair)(this.cryptor, pass, params, midKeyProgressCB)).skey;
|
|
60
|
+
const storeKeyProgressCB = makeKeyGenProgressCB(51, 100, progressCB);
|
|
61
|
+
const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
|
|
62
|
+
return await this.completeInitWithoutCache(midKeyGen, storeKeyGen);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw await this.logAndWrap(err, 'Fail to initialize from a state without cache');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async useExistingStorage(user, pass, progressCB) {
|
|
69
|
+
try {
|
|
70
|
+
const storeKeyProgressCB = makeKeyGenProgressCB(0, 99, progressCB);
|
|
71
|
+
const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
|
|
72
|
+
return await this.initWithCache(user, storeKeyGen);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
throw await this.logAndWrap(err, 'Failing to start in a state with cache');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
91
78
|
async logAndWrap(err, msg) {
|
|
92
79
|
await this.logError(err, msg);
|
|
93
80
|
return (0, error_1.errWithCause)(err, msg);
|
|
@@ -15,14 +15,18 @@ export declare class SignUp {
|
|
|
15
15
|
private cryptor;
|
|
16
16
|
private makeNet;
|
|
17
17
|
private getUsersOnDisk;
|
|
18
|
+
private initForNewUser;
|
|
19
|
+
private readonly watchBoot;
|
|
18
20
|
private readonly logError;
|
|
19
21
|
private mid;
|
|
20
22
|
private store;
|
|
21
23
|
private serviceURL;
|
|
22
24
|
private netLazyInit;
|
|
23
25
|
private get net();
|
|
24
|
-
constructor(serviceURL: string, cryptor: Cryptor, makeNet: () => NetClient, getUsersOnDisk: GetUsersOnDisk, logError: LogError);
|
|
26
|
+
constructor(serviceURL: string, cryptor: Cryptor, makeNet: () => NetClient, getUsersOnDisk: GetUsersOnDisk, initForNewUser: (u: CreatedUser) => Promise<void>, watchBoot: SignUpService['watchBoot'], logError: LogError);
|
|
25
27
|
private setServiceURL;
|
|
28
|
+
private getAvailableDomains;
|
|
29
|
+
private getAvailableAddresses;
|
|
26
30
|
exposedService(): SignUpService;
|
|
27
31
|
private createUserParams;
|
|
28
32
|
private genStorageParams;
|
|
@@ -30,8 +34,6 @@ export declare class SignUp {
|
|
|
30
34
|
private addUser;
|
|
31
35
|
private logAndWrap;
|
|
32
36
|
private forgetKeys;
|
|
33
|
-
private doneBroadcast;
|
|
34
|
-
newUser$: import("rxjs").Observable<CreatedUser>;
|
|
35
37
|
}
|
|
36
38
|
export interface CreatedUser {
|
|
37
39
|
address: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2020, 2022 - 2023 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2020, 2022 - 2023, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -26,7 +26,6 @@ const keyDeriv = require("../../lib-client/key-derivation");
|
|
|
26
26
|
const random = require("../../lib-common/random-node");
|
|
27
27
|
const ecma_nacl_1 = require("ecma-nacl");
|
|
28
28
|
const sign_in_1 = require("./sign-in");
|
|
29
|
-
const rxjs_1 = require("rxjs");
|
|
30
29
|
const error_1 = require("../../lib-common/exceptions/error");
|
|
31
30
|
/**
|
|
32
31
|
* With these parameters scrypt shall use memory around:
|
|
@@ -63,54 +62,21 @@ class SignUp {
|
|
|
63
62
|
}
|
|
64
63
|
return this.netLazyInit;
|
|
65
64
|
}
|
|
66
|
-
constructor(serviceURL, cryptor, makeNet, getUsersOnDisk, logError) {
|
|
65
|
+
constructor(serviceURL, cryptor, makeNet, getUsersOnDisk, initForNewUser, watchBoot, logError) {
|
|
67
66
|
this.cryptor = cryptor;
|
|
68
67
|
this.makeNet = makeNet;
|
|
69
68
|
this.getUsersOnDisk = getUsersOnDisk;
|
|
69
|
+
this.initForNewUser = initForNewUser;
|
|
70
|
+
this.watchBoot = watchBoot;
|
|
70
71
|
this.logError = logError;
|
|
71
72
|
this.mid = undefined;
|
|
72
73
|
this.store = undefined;
|
|
73
74
|
this.serviceURL = undefined;
|
|
74
75
|
this.netLazyInit = undefined;
|
|
75
|
-
this.createUserParams = async (pass, progressCB) => {
|
|
76
|
-
await this.genMidParams(pass, 0, 50, progressCB);
|
|
77
|
-
await this.genStorageParams(pass, 51, 100, progressCB);
|
|
78
|
-
};
|
|
79
|
-
this.addUser = async (address, signupToken) => {
|
|
80
|
-
for (const user of await this.getUsersOnDisk()) {
|
|
81
|
-
if ((0, canonical_address_1.areAddressesEqual)(address, user)) {
|
|
82
|
-
throw new Error(`Account ${user} already exists on a disk.`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const accountCreated = await (0, _3nweb_signup_1.addUser)(this.net, this.serviceURL, {
|
|
86
|
-
userId: address,
|
|
87
|
-
mailerId: this.mid.params,
|
|
88
|
-
storage: this.store.params,
|
|
89
|
-
signupToken
|
|
90
|
-
}).catch(async (err) => {
|
|
91
|
-
throw await this.logAndWrap(err, `Failed to create user account ${address}.`);
|
|
92
|
-
});
|
|
93
|
-
if (!accountCreated) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
this.doneBroadcast.next({
|
|
97
|
-
address,
|
|
98
|
-
midSKey: {
|
|
99
|
-
default: this.mid.defaultSKey,
|
|
100
|
-
labeled: this.mid.labeledSKey
|
|
101
|
-
},
|
|
102
|
-
storeSKey: this.store.skey,
|
|
103
|
-
storeParams: this.store.params.kdParams
|
|
104
|
-
});
|
|
105
|
-
this.forgetKeys();
|
|
106
|
-
return true;
|
|
107
|
-
};
|
|
108
|
-
this.doneBroadcast = new rxjs_1.Subject();
|
|
109
|
-
this.newUser$ = this.doneBroadcast.asObservable();
|
|
110
76
|
this.setServiceURL(serviceURL);
|
|
111
77
|
Object.seal(this);
|
|
112
78
|
}
|
|
113
|
-
setServiceURL(serviceURL) {
|
|
79
|
+
async setServiceURL(serviceURL) {
|
|
114
80
|
const url = (0, url_1.parse)(serviceURL);
|
|
115
81
|
if (url.protocol !== 'https:') {
|
|
116
82
|
throw new Error("Url protocol must be https.");
|
|
@@ -120,17 +86,28 @@ class SignUp {
|
|
|
120
86
|
this.serviceURL += '/';
|
|
121
87
|
}
|
|
122
88
|
}
|
|
89
|
+
async getAvailableDomains(signupToken) {
|
|
90
|
+
return await (0, _3nweb_signup_1.checkAvailableDomains)(this.net, this.serviceURL, signupToken);
|
|
91
|
+
}
|
|
92
|
+
async getAvailableAddresses(name, signupToken) {
|
|
93
|
+
return await (0, _3nweb_signup_1.checkAvailableAddressesForName)(this.net, this.serviceURL, name, signupToken);
|
|
94
|
+
}
|
|
123
95
|
exposedService() {
|
|
124
96
|
const service = {
|
|
125
|
-
setSignUpServer:
|
|
126
|
-
getAvailableDomains:
|
|
127
|
-
addUser: this.addUser,
|
|
128
|
-
createUserParams: this.createUserParams,
|
|
129
|
-
getAvailableAddresses:
|
|
130
|
-
isActivated:
|
|
97
|
+
setSignUpServer: this.setServiceURL.bind(this),
|
|
98
|
+
getAvailableDomains: this.getAvailableDomains.bind(this),
|
|
99
|
+
addUser: this.addUser.bind(this),
|
|
100
|
+
createUserParams: this.createUserParams.bind(this),
|
|
101
|
+
getAvailableAddresses: this.getAvailableAddresses.bind(this),
|
|
102
|
+
isActivated: () => { throw new Error(`Not implemented, yet`); },
|
|
103
|
+
watchBoot: this.watchBoot
|
|
131
104
|
};
|
|
132
105
|
return Object.freeze(service);
|
|
133
106
|
}
|
|
107
|
+
async createUserParams(pass, progressCB) {
|
|
108
|
+
await this.genMidParams(pass, 0, 50, progressCB);
|
|
109
|
+
await this.genStorageParams(pass, 51, 100, progressCB);
|
|
110
|
+
}
|
|
134
111
|
async genStorageParams(pass, progressStart, progressEnd, originalProgressCB) {
|
|
135
112
|
const derivParams = {
|
|
136
113
|
logN: defaultDerivParams.logN,
|
|
@@ -169,6 +146,35 @@ class SignUp {
|
|
|
169
146
|
}
|
|
170
147
|
};
|
|
171
148
|
}
|
|
149
|
+
async addUser(address, signupToken) {
|
|
150
|
+
for (const user of await this.getUsersOnDisk()) {
|
|
151
|
+
if ((0, canonical_address_1.areAddressesEqual)(address, user)) {
|
|
152
|
+
throw new Error(`Account ${user} already exists on a disk.`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const accountCreated = await (0, _3nweb_signup_1.addUser)(this.net, this.serviceURL, {
|
|
156
|
+
userId: address,
|
|
157
|
+
mailerId: this.mid.params,
|
|
158
|
+
storage: this.store.params,
|
|
159
|
+
signupToken
|
|
160
|
+
}).catch(async (err) => {
|
|
161
|
+
throw await this.logAndWrap(err, `Failed to create user account ${address}.`);
|
|
162
|
+
});
|
|
163
|
+
if (!accountCreated) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
this.initForNewUser({
|
|
167
|
+
address,
|
|
168
|
+
midSKey: {
|
|
169
|
+
default: this.mid.defaultSKey,
|
|
170
|
+
labeled: this.mid.labeledSKey
|
|
171
|
+
},
|
|
172
|
+
storeSKey: this.store.skey,
|
|
173
|
+
storeParams: this.store.params.kdParams
|
|
174
|
+
});
|
|
175
|
+
this.forgetKeys();
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
172
178
|
async logAndWrap(err, msg) {
|
|
173
179
|
await this.logError(err, msg);
|
|
174
180
|
return (0, error_1.errWithCause)(err, msg);
|
|
@@ -44,7 +44,8 @@ function wrapSignInCAP(cap) {
|
|
|
44
44
|
(_b = obs.complete) === null || _b === void 0 ? void 0 : _b.call(obs);
|
|
45
45
|
}, err => { var _a; return (_a = obs.error) === null || _a === void 0 ? void 0 : _a.call(obs, err); });
|
|
46
46
|
return noop;
|
|
47
|
-
})
|
|
47
|
+
}),
|
|
48
|
+
watchBoot: (0, service_side_wrap_1.wrapObservingFunc)(cap.watchBoot)
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
51
|
function makeSignInCaller(caller, objPath) {
|
|
@@ -66,7 +67,8 @@ function makeSignInCaller(caller, objPath) {
|
|
|
66
67
|
obsFn(obs, addr, pass);
|
|
67
68
|
return promise;
|
|
68
69
|
};
|
|
69
|
-
})()
|
|
70
|
+
})(),
|
|
71
|
+
watchBoot: (0, caller_side_wrap_1.makeObservableFuncCaller)(caller, objPath.concat('watchBoot'))
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
function callSignIn(caller, objPath, method) {
|
|
@@ -104,7 +106,8 @@ function wrapSignUpCAP(cap) {
|
|
|
104
106
|
.then(() => { var _a; return (_a = obs.complete) === null || _a === void 0 ? void 0 : _a.call(obs); }, err => { var _a; return (_a = obs.error) === null || _a === void 0 ? void 0 : _a.call(obs, err); });
|
|
105
107
|
return noop;
|
|
106
108
|
}),
|
|
107
|
-
isActivated: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'isActivated')
|
|
109
|
+
isActivated: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'isActivated'),
|
|
110
|
+
watchBoot: (0, service_side_wrap_1.wrapObservingFunc)(cap.watchBoot)
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
function noop() { }
|
|
@@ -129,7 +132,8 @@ function makeSignUpCaller(caller, objPath) {
|
|
|
129
132
|
return completion.promise;
|
|
130
133
|
};
|
|
131
134
|
})(),
|
|
132
|
-
isActivated: callSignUp(caller, objPath, 'isActivated')
|
|
135
|
+
isActivated: callSignUp(caller, objPath, 'isActivated'),
|
|
136
|
+
watchBoot: (0, caller_side_wrap_1.makeObservableFuncCaller)(caller, objPath.concat('watchBoot'))
|
|
133
137
|
};
|
|
134
138
|
}
|
|
135
139
|
Object.freeze(exports);
|
|
@@ -24,6 +24,7 @@ exports.getMailerIdInfoFor = getMailerIdInfoFor;
|
|
|
24
24
|
const jwkeys_1 = require("../lib-common/jwkeys");
|
|
25
25
|
const url_1 = require("url");
|
|
26
26
|
const request_utils_1 = require("./request-utils");
|
|
27
|
+
const runtime_1 = require("../lib-common/exceptions/runtime");
|
|
27
28
|
async function readJSONLocatedAt(client, url) {
|
|
28
29
|
if ((0, url_1.parse)(url).protocol !== 'https:') {
|
|
29
30
|
throw new Error("Url protocol must be https.");
|
|
@@ -143,23 +144,17 @@ function checkAndPrepareURL(value) {
|
|
|
143
144
|
return 'https://' + value;
|
|
144
145
|
}
|
|
145
146
|
function domainNotFoundExc(address, cause) {
|
|
146
|
-
|
|
147
|
-
runtimeException: true,
|
|
148
|
-
type: 'service-locating',
|
|
149
|
-
address,
|
|
150
|
-
domainNotFound: true,
|
|
151
|
-
cause
|
|
152
|
-
};
|
|
153
|
-
return exc;
|
|
147
|
+
return (0, runtime_1.makeRuntimeException)('service-locating', { address, cause }, { domainNotFound: true });
|
|
154
148
|
}
|
|
155
149
|
function noServiceRecordExc(address) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
150
|
+
return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { noServiceRecord: true });
|
|
151
|
+
}
|
|
152
|
+
function noConnectionExc(cause) {
|
|
153
|
+
return (0, runtime_1.makeRuntimeException)('connect', {
|
|
154
|
+
connectType: 'dns',
|
|
155
|
+
message: `The most likely cause of this error is device not connected. Next likely cause is DNS not setup, or not connecting properly. Like the saying goes: "It's not DNS. There is no way it's DNS. It was DNS."`,
|
|
156
|
+
cause
|
|
157
|
+
}, {});
|
|
163
158
|
}
|
|
164
159
|
/**
|
|
165
160
|
* This implementation extracts exactly one string value for a given service.
|
|
@@ -227,7 +222,8 @@ function getRecordAtStartOf(txt) {
|
|
|
227
222
|
}
|
|
228
223
|
const DNS_ERR_CODE = {
|
|
229
224
|
NODATA: 'ENODATA',
|
|
230
|
-
NOTFOUND: 'ENOTFOUND'
|
|
225
|
+
NOTFOUND: 'ENOTFOUND',
|
|
226
|
+
ESERVFAIL: 'ESERVFAIL'
|
|
231
227
|
};
|
|
232
228
|
Object.freeze(DNS_ERR_CODE);
|
|
233
229
|
function makeServiceLocator(resolver) {
|
|
@@ -247,6 +243,9 @@ function makeServiceLocator(resolver) {
|
|
|
247
243
|
if (code === DNS_ERR_CODE.NODATA) {
|
|
248
244
|
throw noServiceRecordExc(address);
|
|
249
245
|
}
|
|
246
|
+
else if (code === DNS_ERR_CODE.ESERVFAIL) {
|
|
247
|
+
throw noConnectionExc({ code, hostname, message });
|
|
248
|
+
}
|
|
250
249
|
else if (hostname) {
|
|
251
250
|
throw domainNotFoundExc(address, { code, hostname, message });
|
|
252
251
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ConnectException = web3n.
|
|
1
|
+
export type ConnectException = web3n.HTTPConnectException;
|
|
2
2
|
export type HTTPException = web3n.HTTPException;
|
|
3
|
-
export declare function makeConnectionException(url: string | undefined, method: string | undefined,
|
|
4
|
-
export declare function makeHTTPException(url: string, method: string, status: number,
|
|
3
|
+
export declare function makeConnectionException(url: string | undefined, method: string | undefined, message?: string, cause?: any): ConnectException;
|
|
4
|
+
export declare function makeHTTPException(url: string, method: string, status: number, message?: string, cause?: any): HTTPException;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -17,31 +17,11 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.makeConnectionException = makeConnectionException;
|
|
19
19
|
exports.makeHTTPException = makeHTTPException;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
type: 'http-connect',
|
|
24
|
-
url: url,
|
|
25
|
-
method: method,
|
|
26
|
-
cause
|
|
27
|
-
};
|
|
28
|
-
if (msg) {
|
|
29
|
-
exc.message = msg;
|
|
30
|
-
}
|
|
31
|
-
return exc;
|
|
20
|
+
const runtime_1 = require("./runtime");
|
|
21
|
+
function makeConnectionException(url, method, message, cause) {
|
|
22
|
+
return (0, runtime_1.makeRuntimeException)('connect', { connectType: 'http', url, method, cause, message }, {});
|
|
32
23
|
}
|
|
33
|
-
function makeHTTPException(url, method, status,
|
|
34
|
-
|
|
35
|
-
runtimeException: true,
|
|
36
|
-
type: 'http-request',
|
|
37
|
-
url: url,
|
|
38
|
-
method: method,
|
|
39
|
-
status: status,
|
|
40
|
-
cause
|
|
41
|
-
};
|
|
42
|
-
if (msg) {
|
|
43
|
-
exc.message = msg;
|
|
44
|
-
}
|
|
45
|
-
return exc;
|
|
24
|
+
function makeHTTPException(url, method, status, message, cause) {
|
|
25
|
+
return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, cause, message }, {});
|
|
46
26
|
}
|
|
47
27
|
Object.freeze(exports);
|