@webda/core 2.0.0-beta.1 → 2.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/lib/application.d.ts +9 -21
- package/lib/application.js +71 -84
- package/lib/application.js.map +1 -1
- package/lib/application.spec.js +121 -140
- package/lib/application.spec.js.map +1 -1
- package/lib/core.d.ts +86 -46
- package/lib/core.js +254 -316
- package/lib/core.js.map +1 -1
- package/lib/core.spec.js +326 -391
- package/lib/core.spec.js.map +1 -1
- package/lib/index.d.ts +49 -45
- package/lib/index.js +54 -67
- package/lib/index.js.map +1 -1
- package/lib/models/aclmodel.d.ts +2 -2
- package/lib/models/aclmodel.js +63 -90
- package/lib/models/aclmodel.js.map +1 -1
- package/lib/models/aclmodel.spec.js +127 -151
- package/lib/models/aclmodel.spec.js.map +1 -1
- package/lib/models/coremodel.d.ts +84 -11
- package/lib/models/coremodel.js +104 -103
- package/lib/models/coremodel.js.map +1 -1
- package/lib/models/coremodel.spec.js +91 -91
- package/lib/models/coremodel.spec.js.map +1 -1
- package/lib/models/deployment.js +1 -2
- package/lib/models/ident.d.ts +5 -3
- package/lib/models/ident.js +4 -9
- package/lib/models/ident.js.map +1 -1
- package/lib/models/ident.spec.js +9 -11
- package/lib/models/ident.spec.js.map +1 -1
- package/lib/models/ownermodel.d.ts +12 -2
- package/lib/models/ownermodel.js +54 -62
- package/lib/models/ownermodel.js.map +1 -1
- package/lib/models/ownermodel.spec.js +129 -152
- package/lib/models/ownermodel.spec.js.map +1 -1
- package/lib/models/rolemodel.d.ts +2 -2
- package/lib/models/rolemodel.js +24 -40
- package/lib/models/rolemodel.js.map +1 -1
- package/lib/models/rolemodel.spec.js +44 -61
- package/lib/models/rolemodel.spec.js.map +1 -1
- package/lib/models/user.d.ts +5 -5
- package/lib/models/user.js +3 -8
- package/lib/models/user.js.map +1 -1
- package/lib/models/user.spec.js +14 -16
- package/lib/models/user.spec.js.map +1 -1
- package/lib/queues/filequeue.d.ts +2 -2
- package/lib/queues/filequeue.js +72 -93
- package/lib/queues/filequeue.js.map +1 -1
- package/lib/queues/filequeue.spec.js +53 -70
- package/lib/queues/filequeue.spec.js.map +1 -1
- package/lib/queues/memoryqueue.d.ts +2 -2
- package/lib/queues/memoryqueue.js +37 -61
- package/lib/queues/memoryqueue.js.map +1 -1
- package/lib/queues/memoryqueue.spec.js +142 -165
- package/lib/queues/memoryqueue.spec.js.map +1 -1
- package/lib/queues/pubsubservice.d.ts +2 -2
- package/lib/queues/pubsubservice.js +3 -7
- package/lib/queues/pubsubservice.js.map +1 -1
- package/lib/queues/queue.spec.d.ts +1 -1
- package/lib/queues/queue.spec.js +42 -56
- package/lib/queues/queue.spec.js.map +1 -1
- package/lib/queues/queueservice.d.ts +4 -4
- package/lib/queues/queueservice.js +52 -67
- package/lib/queues/queueservice.js.map +1 -1
- package/lib/router.d.ts +7 -3
- package/lib/router.js +49 -48
- package/lib/router.js.map +1 -1
- package/lib/router.spec.js +64 -61
- package/lib/router.spec.js.map +1 -1
- package/lib/services/asyncevents.d.ts +2 -2
- package/lib/services/asyncevents.js +44 -64
- package/lib/services/asyncevents.js.map +1 -1
- package/lib/services/asyncevents.spec.js +81 -98
- package/lib/services/asyncevents.spec.js.map +1 -1
- package/lib/services/authentication.d.ts +28 -19
- package/lib/services/authentication.js +539 -571
- package/lib/services/authentication.js.map +1 -1
- package/lib/services/authentication.spec.js +411 -447
- package/lib/services/authentication.spec.js.map +1 -1
- package/lib/services/binary.d.ts +8 -6
- package/lib/services/binary.js +212 -244
- package/lib/services/binary.js.map +1 -1
- package/lib/services/binary.spec.d.ts +3 -3
- package/lib/services/binary.spec.js +390 -443
- package/lib/services/binary.spec.js.map +1 -1
- package/lib/services/cloudbinary.d.ts +3 -3
- package/lib/services/cloudbinary.js +46 -71
- package/lib/services/cloudbinary.js.map +1 -1
- package/lib/services/cloudbinary.spec.d.ts +3 -3
- package/lib/services/cloudbinary.spec.js +133 -162
- package/lib/services/cloudbinary.spec.js.map +1 -1
- package/lib/services/configuration.d.ts +6 -3
- package/lib/services/configuration.js +78 -103
- package/lib/services/configuration.js.map +1 -1
- package/lib/services/configuration.spec.js +63 -83
- package/lib/services/configuration.spec.js.map +1 -1
- package/lib/services/cron.d.ts +3 -2
- package/lib/services/cron.js +9 -13
- package/lib/services/cron.js.map +1 -1
- package/lib/services/cron.spec.js +18 -21
- package/lib/services/cron.spec.js.map +1 -1
- package/lib/services/cryptoservice.d.ts +258 -0
- package/lib/services/cryptoservice.js +312 -0
- package/lib/services/cryptoservice.js.map +1 -0
- package/lib/services/cryptoservice.spec.d.ts +1 -0
- package/lib/services/cryptoservice.spec.js +137 -0
- package/lib/services/cryptoservice.spec.js.map +1 -0
- package/lib/services/debugmailer.d.ts +1 -1
- package/lib/services/debugmailer.js +13 -34
- package/lib/services/debugmailer.js.map +1 -1
- package/lib/services/debugmailer.spec.js +16 -29
- package/lib/services/debugmailer.spec.js.map +1 -1
- package/lib/services/echo.d.ts +2 -2
- package/lib/services/echo.js +15 -31
- package/lib/services/echo.js.map +1 -1
- package/lib/services/echo.spec.js +27 -40
- package/lib/services/echo.spec.js.map +1 -1
- package/lib/services/filebinary.d.ts +15 -5
- package/lib/services/filebinary.js +171 -200
- package/lib/services/filebinary.js.map +1 -1
- package/lib/services/filebinary.spec.d.ts +2 -1
- package/lib/services/filebinary.spec.js +106 -117
- package/lib/services/filebinary.spec.js.map +1 -1
- package/lib/services/fileconfiguration.d.ts +2 -2
- package/lib/services/fileconfiguration.js +25 -43
- package/lib/services/fileconfiguration.js.map +1 -1
- package/lib/services/fileconfiguration.spec.js +79 -109
- package/lib/services/fileconfiguration.spec.js.map +1 -1
- package/lib/services/invitationservice.d.ts +9 -9
- package/lib/services/invitationservice.js +275 -313
- package/lib/services/invitationservice.js.map +1 -1
- package/lib/services/invitationservice.spec.js +442 -448
- package/lib/services/invitationservice.spec.js.map +1 -1
- package/lib/services/kubernetesconfiguration.d.ts +2 -2
- package/lib/services/kubernetesconfiguration.js +41 -59
- package/lib/services/kubernetesconfiguration.js.map +1 -1
- package/lib/services/kubernetesconfiguration.spec.js +80 -98
- package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
- package/lib/services/mailer.d.ts +4 -4
- package/lib/services/mailer.js +62 -86
- package/lib/services/mailer.js.map +1 -1
- package/lib/services/mailer.spec.js +86 -127
- package/lib/services/mailer.spec.js.map +1 -1
- package/lib/services/notificationservice.d.ts +4 -4
- package/lib/services/notificationservice.js +23 -42
- package/lib/services/notificationservice.js.map +1 -1
- package/lib/services/notificationservice.spec.js +47 -73
- package/lib/services/notificationservice.spec.js.map +1 -1
- package/lib/services/oauth.d.ts +32 -6
- package/lib/services/oauth.js +73 -78
- package/lib/services/oauth.js.map +1 -1
- package/lib/services/oauth.spec.js +128 -147
- package/lib/services/oauth.spec.js.map +1 -1
- package/lib/services/proxy.d.ts +74 -0
- package/lib/services/proxy.js +126 -0
- package/lib/services/proxy.js.map +1 -0
- package/lib/services/proxy.spec.d.ts +1 -0
- package/lib/services/proxy.spec.js +59 -0
- package/lib/services/proxy.spec.js.map +1 -0
- package/lib/services/resource.d.ts +2 -2
- package/lib/services/resource.js +12 -18
- package/lib/services/resource.js.map +1 -1
- package/lib/services/resource.spec.js +67 -99
- package/lib/services/resource.spec.js.map +1 -1
- package/lib/services/service.d.ts +33 -7
- package/lib/services/service.js +74 -42
- package/lib/services/service.js.map +1 -1
- package/lib/services/service.spec.js +62 -67
- package/lib/services/service.spec.js.map +1 -1
- package/lib/services/version.d.ts +1 -1
- package/lib/services/version.js +3 -8
- package/lib/services/version.js.map +1 -1
- package/lib/services/version.spec.js +11 -24
- package/lib/services/version.spec.js.map +1 -1
- package/lib/stores/aggregator.d.ts +3 -3
- package/lib/stores/aggregator.js +37 -57
- package/lib/stores/aggregator.js.map +1 -1
- package/lib/stores/file.d.ts +3 -3
- package/lib/stores/file.js +93 -131
- package/lib/stores/file.js.map +1 -1
- package/lib/stores/file.spec.d.ts +2 -2
- package/lib/stores/file.spec.js +261 -289
- package/lib/stores/file.spec.js.map +1 -1
- package/lib/stores/mapper.d.ts +4 -4
- package/lib/stores/mapper.js +112 -137
- package/lib/stores/mapper.js.map +1 -1
- package/lib/stores/mapper.spec.js +131 -150
- package/lib/stores/mapper.spec.js.map +1 -1
- package/lib/stores/memory.d.ts +67 -6
- package/lib/stores/memory.js +155 -117
- package/lib/stores/memory.js.map +1 -1
- package/lib/stores/memory.spec.d.ts +3 -2
- package/lib/stores/memory.spec.js +127 -105
- package/lib/stores/memory.spec.js.map +1 -1
- package/lib/stores/store.d.ts +35 -15
- package/lib/stores/store.js +839 -821
- package/lib/stores/store.js.map +1 -1
- package/lib/stores/store.spec.d.ts +6 -4
- package/lib/stores/store.spec.js +627 -647
- package/lib/stores/store.spec.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLLexer.d.ts +4 -4
- package/lib/stores/webdaql/WebdaQLLexer.js +9 -13
- package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +4 -4
- package/lib/stores/webdaql/WebdaQLParserLexer.js +9 -13
- package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserListener.d.ts +2 -2
- package/lib/stores/webdaql/WebdaQLParserListener.js +1 -2
- package/lib/stores/webdaql/WebdaQLParserListener.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserParser.d.ts +10 -10
- package/lib/stores/webdaql/WebdaQLParserParser.js +62 -91
- package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +2 -2
- package/lib/stores/webdaql/WebdaQLParserVisitor.js +1 -2
- package/lib/stores/webdaql/WebdaQLParserVisitor.js.map +1 -1
- package/lib/stores/webdaql/query.d.ts +4 -5
- package/lib/stores/webdaql/query.js +16 -19
- package/lib/stores/webdaql/query.js.map +1 -1
- package/lib/stores/webdaql/query.spec.js +30 -32
- package/lib/stores/webdaql/query.spec.js.map +1 -1
- package/lib/test.d.ts +3 -3
- package/lib/test.js +74 -94
- package/lib/test.js.map +1 -1
- package/lib/unpackedapplication.d.ts +1 -1
- package/lib/unpackedapplication.js +25 -31
- package/lib/unpackedapplication.js.map +1 -1
- package/lib/utils/abstractdeployer.js +1 -5
- package/lib/utils/abstractdeployer.js.map +1 -1
- package/lib/utils/abstractdeployer.spec.js +6 -8
- package/lib/utils/abstractdeployer.spec.js.map +1 -1
- package/lib/utils/context.d.ts +61 -29
- package/lib/utils/context.js +133 -127
- package/lib/utils/context.js.map +1 -1
- package/lib/utils/context.spec.js +147 -153
- package/lib/utils/context.spec.js.map +1 -1
- package/lib/utils/cookie.d.ts +66 -45
- package/lib/utils/cookie.js +69 -158
- package/lib/utils/cookie.js.map +1 -1
- package/lib/utils/cookie.spec.js +220 -238
- package/lib/utils/cookie.spec.js.map +1 -1
- package/lib/utils/esm.d.ts +4 -0
- package/lib/utils/esm.js +10 -0
- package/lib/utils/esm.js.map +1 -0
- package/lib/utils/httpcontext.d.ts +37 -9
- package/lib/utils/httpcontext.js +86 -57
- package/lib/utils/httpcontext.js.map +1 -1
- package/lib/utils/httpcontext.spec.js +37 -48
- package/lib/utils/httpcontext.spec.js.map +1 -1
- package/lib/utils/logger.d.ts +2 -2
- package/lib/utils/logger.js +15 -28
- package/lib/utils/logger.js.map +1 -1
- package/lib/utils/logger.spec.js +9 -11
- package/lib/utils/logger.spec.js.map +1 -1
- package/lib/utils/serializers.js +17 -20
- package/lib/utils/serializers.js.map +1 -1
- package/lib/utils/serializers.spec.js +43 -44
- package/lib/utils/serializers.spec.js.map +1 -1
- package/lib/utils/session.d.ts +120 -0
- package/lib/utils/session.js +155 -0
- package/lib/utils/session.js.map +1 -0
- package/lib/utils/session.spec.d.ts +1 -0
- package/lib/utils/session.spec.js +66 -0
- package/lib/utils/session.spec.js.map +1 -0
- package/lib/utils/waiter.d.ts +1 -1
- package/lib/utils/waiter.js +32 -52
- package/lib/utils/waiter.js.map +1 -1
- package/lib/utils/waiter.spec.js +75 -92
- package/lib/utils/waiter.spec.js.map +1 -1
- package/package.json +22 -14
- package/test/config-invitation.json +1 -3
- package/test/config.json +3 -3
- package/test/config.old.json +1 -2
- package/test/moddas/annotatedservice.js +5 -5
- package/test/moddas/debugmailer.js +2 -3
- package/test/moddas/fakeservice.js +2 -3
- package/test/moddas/voidstore.js +6 -4
- package/test/models/ident.js +2 -6
- package/test/models/task.js +3 -7
- package/test/package.json +2 -1
- package/webda.module.json +956 -188
|
@@ -1,43 +1,28 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
13
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
14
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.Authentication = exports.AuthenticationParameters = void 0;
|
|
19
|
-
const bcrypt = require("bcryptjs");
|
|
20
|
-
const crypto = require("crypto");
|
|
21
|
-
const service_1 = require("../services/service");
|
|
22
|
-
const httpcontext_1 = require("../utils/httpcontext");
|
|
23
|
-
class AuthenticationParameters extends service_1.ServiceParameters {
|
|
7
|
+
import bcrypt from "bcryptjs";
|
|
8
|
+
import { Inject, Route, Service, ServiceParameters } from "../services/service.js";
|
|
9
|
+
import { HttpContext } from "../utils/httpcontext.js";
|
|
10
|
+
export class AuthenticationParameters extends ServiceParameters {
|
|
24
11
|
constructor(params) {
|
|
25
|
-
var _a, _b
|
|
26
|
-
var _g, _h;
|
|
12
|
+
var _a, _b;
|
|
27
13
|
super(params);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
this.identStore ?? (this.identStore = "idents");
|
|
15
|
+
this.userStore ?? (this.userStore = "users");
|
|
16
|
+
this.url ?? (this.url = "/auth");
|
|
17
|
+
this.password ?? (this.password = {
|
|
32
18
|
regexp: ".{8,}"
|
|
33
19
|
});
|
|
34
20
|
if (this.email) {
|
|
35
|
-
(
|
|
36
|
-
(
|
|
21
|
+
(_a = this.email).delay ?? (_a.delay = 3600000 * 4);
|
|
22
|
+
(_b = this.email).failedLoginBeforeDelay ?? (_b.failedLoginBeforeDelay = 3);
|
|
37
23
|
}
|
|
38
24
|
}
|
|
39
25
|
}
|
|
40
|
-
exports.AuthenticationParameters = AuthenticationParameters;
|
|
41
26
|
/**
|
|
42
27
|
* This class is known as the Authentication module
|
|
43
28
|
* It handles OAuth for several providers for now (Facebook, Google, Amazon, GitHub and Twitter)
|
|
@@ -61,7 +46,7 @@ exports.AuthenticationParameters = AuthenticationParameters;
|
|
|
61
46
|
* @category CoreServices
|
|
62
47
|
* @WebdaModda
|
|
63
48
|
*/
|
|
64
|
-
class Authentication extends
|
|
49
|
+
class Authentication extends Service {
|
|
65
50
|
constructor() {
|
|
66
51
|
super(...arguments);
|
|
67
52
|
this.providers = new Set();
|
|
@@ -86,132 +71,6 @@ class Authentication extends service_1.Service {
|
|
|
86
71
|
getIdentStore() {
|
|
87
72
|
return this._identsStore;
|
|
88
73
|
}
|
|
89
|
-
/**
|
|
90
|
-
* @override
|
|
91
|
-
*/
|
|
92
|
-
initRoutes() {
|
|
93
|
-
// ROUTES
|
|
94
|
-
let url = this.parameters.url;
|
|
95
|
-
// List authentication configured
|
|
96
|
-
this.addRoute(url, ["GET", "DELETE"], this._listAuthentications, {
|
|
97
|
-
get: {
|
|
98
|
-
description: "Retrieve the list of available authentication",
|
|
99
|
-
summary: "Get available auths",
|
|
100
|
-
operationId: `getAuthenticationMethods`,
|
|
101
|
-
responses: {
|
|
102
|
-
"200": {
|
|
103
|
-
description: "List of authentication"
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
delete: {
|
|
108
|
-
description: "Logout current user",
|
|
109
|
-
summary: "Logout",
|
|
110
|
-
operationId: `logout`,
|
|
111
|
-
responses: {
|
|
112
|
-
"200": {}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
// Get the current user
|
|
117
|
-
this.addRoute(url + "/me", ["GET"], this._getMe, {
|
|
118
|
-
get: {
|
|
119
|
-
description: "Retrieve the current user from the session",
|
|
120
|
-
summary: "Get current user",
|
|
121
|
-
operationId: "getCurrentUser"
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
if (this.parameters.email) {
|
|
125
|
-
this.addProvider("email");
|
|
126
|
-
// Add static for email for now, if set before it should have priority
|
|
127
|
-
this.addRoute(url + "/email", ["POST"], this._handleEmail, {
|
|
128
|
-
post: {
|
|
129
|
-
description: "Authenticate with an email and password",
|
|
130
|
-
summary: "Authenticate with email",
|
|
131
|
-
operationId: `authWithEmail`
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
this.addRoute(url + "/email/callback{?email,token,user}", ["GET"], this._handleEmailCallback, {
|
|
135
|
-
hidden: true
|
|
136
|
-
});
|
|
137
|
-
this.addRoute(url + "/email/passwordRecovery", ["POST"], this._passwordRecovery, {
|
|
138
|
-
post: {
|
|
139
|
-
schemas: {
|
|
140
|
-
input: {
|
|
141
|
-
type: "object",
|
|
142
|
-
properties: {
|
|
143
|
-
token: {
|
|
144
|
-
type: "string"
|
|
145
|
-
},
|
|
146
|
-
expire: {
|
|
147
|
-
type: "number"
|
|
148
|
-
},
|
|
149
|
-
password: {
|
|
150
|
-
type: "string"
|
|
151
|
-
},
|
|
152
|
-
login: {
|
|
153
|
-
type: "string"
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
description: "Reinit the password if we have the right token, expire",
|
|
159
|
-
summary: "Reinit password",
|
|
160
|
-
operationId: "reinitPassword",
|
|
161
|
-
responses: {
|
|
162
|
-
"204": {
|
|
163
|
-
description: ""
|
|
164
|
-
},
|
|
165
|
-
"403": {
|
|
166
|
-
description: "Wrong Token"
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
this.addRoute(url + "/email/{email}/recover", ["GET"], this._passwordRecoveryEmail, {
|
|
172
|
-
get: {
|
|
173
|
-
description: "The password reset process will be start",
|
|
174
|
-
summary: "Start password recovery",
|
|
175
|
-
operationId: "startEmailRecovery",
|
|
176
|
-
responses: {
|
|
177
|
-
"204": {
|
|
178
|
-
description: ""
|
|
179
|
-
},
|
|
180
|
-
"404": {
|
|
181
|
-
description: "Email does not exist"
|
|
182
|
-
},
|
|
183
|
-
"429": {
|
|
184
|
-
description: "Recovery has been initiated in the last 4 hours"
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
this.addRoute(url + "/email/{email}/validate", ["GET"], this._sendEmailValidation, {
|
|
190
|
-
get: {
|
|
191
|
-
description: "The email validation process will be start",
|
|
192
|
-
summary: "Restart email validation",
|
|
193
|
-
operationId: "startEmailRecovery",
|
|
194
|
-
responses: {
|
|
195
|
-
"204": {
|
|
196
|
-
description: ""
|
|
197
|
-
},
|
|
198
|
-
"409": {
|
|
199
|
-
description: "Email already verified for another user"
|
|
200
|
-
},
|
|
201
|
-
"412": {
|
|
202
|
-
description: "Email already verified for current user"
|
|
203
|
-
},
|
|
204
|
-
"429": {
|
|
205
|
-
description: "Validation has been initiated in the last 4 hours"
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
getUrl() {
|
|
213
|
-
return this.parameters.url;
|
|
214
|
-
}
|
|
215
74
|
setIdents(identStore) {
|
|
216
75
|
this._identsStore = identStore;
|
|
217
76
|
}
|
|
@@ -230,6 +89,10 @@ class Authentication extends service_1.Service {
|
|
|
230
89
|
if (this.parameters.email && this.getMailMan() === undefined) {
|
|
231
90
|
throw Error("email authentication requires a Mailer service");
|
|
232
91
|
}
|
|
92
|
+
// Add email provider
|
|
93
|
+
if (this.parameters.email) {
|
|
94
|
+
this.addProvider("email");
|
|
95
|
+
}
|
|
233
96
|
}
|
|
234
97
|
/**
|
|
235
98
|
* Add a provider to the oauth scheme
|
|
@@ -238,6 +101,16 @@ class Authentication extends service_1.Service {
|
|
|
238
101
|
addProvider(name) {
|
|
239
102
|
this.providers.add(name);
|
|
240
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Ensure email is enabled for all emails routes
|
|
106
|
+
* @override
|
|
107
|
+
*/
|
|
108
|
+
getUrl(url, methods) {
|
|
109
|
+
if (url.startsWith("./emails") && !this.parameters.email) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
return super.getUrl(url, methods);
|
|
113
|
+
}
|
|
241
114
|
/**
|
|
242
115
|
* Send or resend an email to validate the email address
|
|
243
116
|
*
|
|
@@ -246,54 +119,50 @@ class Authentication extends service_1.Service {
|
|
|
246
119
|
* @throws 412 if the email is already validated
|
|
247
120
|
* @throws 429 if a validation email has been sent recently
|
|
248
121
|
*/
|
|
249
|
-
_sendEmailValidation(ctx) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
122
|
+
async _sendEmailValidation(ctx) {
|
|
123
|
+
let identKey = ctx.parameters.email + "_email";
|
|
124
|
+
let ident = await this._identsStore.get(identKey);
|
|
125
|
+
if (!ident) {
|
|
126
|
+
await this._identsStore.save({
|
|
127
|
+
uuid: `${ctx.parameters.email}_email`,
|
|
128
|
+
_lastValidationEmail: Date.now(),
|
|
129
|
+
_type: "email"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// If the ident is linked to someone else - might want to remove it
|
|
134
|
+
if (ident.getUser() !== ctx.getCurrentUserId()) {
|
|
135
|
+
throw 409;
|
|
259
136
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
throw 409;
|
|
264
|
-
}
|
|
265
|
-
// If the email is already validated
|
|
266
|
-
if (ident._validation) {
|
|
267
|
-
throw 412;
|
|
268
|
-
}
|
|
269
|
-
//
|
|
270
|
-
if (ident._lastValidationEmail >= Date.now() - this.parameters.email.delay) {
|
|
271
|
-
throw 429;
|
|
272
|
-
}
|
|
273
|
-
yield this._identsStore.patch({
|
|
274
|
-
_lastValidationEmail: Date.now(),
|
|
275
|
-
uuid: identKey
|
|
276
|
-
});
|
|
137
|
+
// If the email is already validated
|
|
138
|
+
if (ident._validation) {
|
|
139
|
+
throw 412;
|
|
277
140
|
}
|
|
278
|
-
|
|
279
|
-
|
|
141
|
+
//
|
|
142
|
+
if (ident._lastValidationEmail >= Date.now() - this.parameters.email.delay) {
|
|
143
|
+
throw 429;
|
|
144
|
+
}
|
|
145
|
+
await this._identsStore.patch({
|
|
146
|
+
_lastValidationEmail: Date.now(),
|
|
147
|
+
uuid: identKey
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
await this.sendValidationEmail(ctx, ctx.parameters.email);
|
|
280
151
|
}
|
|
281
152
|
/**
|
|
282
153
|
* Return current user
|
|
283
154
|
* @param ctx
|
|
284
155
|
*/
|
|
285
|
-
_getMe(ctx) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
user
|
|
294
|
-
});
|
|
295
|
-
ctx.write(user);
|
|
156
|
+
async _getMe(ctx) {
|
|
157
|
+
let user = await ctx.getCurrentUser();
|
|
158
|
+
if (user === undefined) {
|
|
159
|
+
throw 404;
|
|
160
|
+
}
|
|
161
|
+
await this.emitSync("Authentication.GetMe", {
|
|
162
|
+
context: ctx,
|
|
163
|
+
user
|
|
296
164
|
});
|
|
165
|
+
ctx.write(user);
|
|
297
166
|
}
|
|
298
167
|
/**
|
|
299
168
|
* Handle both list of available authentication
|
|
@@ -302,233 +171,223 @@ class Authentication extends service_1.Service {
|
|
|
302
171
|
* @param ctx
|
|
303
172
|
* @returns
|
|
304
173
|
*/
|
|
305
|
-
_listAuthentications(ctx) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
ctx.write(Array.from(this.providers));
|
|
313
|
-
});
|
|
174
|
+
async _listAuthentications(ctx) {
|
|
175
|
+
if (ctx.getHttpContext().getMethod() === "DELETE") {
|
|
176
|
+
await this.logout(ctx);
|
|
177
|
+
ctx.write("GoodBye");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
ctx.write(Array.from(this.providers));
|
|
314
181
|
}
|
|
315
|
-
onIdentLogin(ctx, provider, identId, profile, tokens = undefined) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
182
|
+
async onIdentLogin(ctx, provider, identId, profile, tokens = undefined) {
|
|
183
|
+
// Auto postifx with provider name
|
|
184
|
+
const postfix = `_${provider}`;
|
|
185
|
+
if (!identId.endsWith(postfix)) {
|
|
186
|
+
identId += postfix;
|
|
187
|
+
}
|
|
188
|
+
let ident = await this._identsStore.get(identId);
|
|
189
|
+
// Ident is known
|
|
190
|
+
if (ident) {
|
|
191
|
+
await this.login(ctx, ident.getUser(), ident);
|
|
192
|
+
await this._identsStore.patch({
|
|
193
|
+
_lastUsed: new Date(),
|
|
194
|
+
__tokens: tokens,
|
|
195
|
+
uuid: ident.uuid
|
|
196
|
+
});
|
|
197
|
+
// Redirect to?
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
let user;
|
|
201
|
+
if (profile.email) {
|
|
202
|
+
ident = await this._identsStore.get(`${profile.email}_email`);
|
|
203
|
+
}
|
|
204
|
+
// If already login
|
|
205
|
+
if (ctx.getCurrentUserId()) {
|
|
206
|
+
user = await ctx.getCurrentUser();
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// If an email in profile try to find the ident
|
|
324
210
|
if (ident) {
|
|
325
|
-
|
|
326
|
-
yield this._identsStore.patch({
|
|
327
|
-
_lastUsed: new Date(),
|
|
328
|
-
__tokens: tokens,
|
|
329
|
-
uuid: ident.uuid
|
|
330
|
-
});
|
|
331
|
-
// Redirect to?
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
let user;
|
|
335
|
-
if (profile.email) {
|
|
336
|
-
ident = yield this._identsStore.get(`${profile.email}_email`);
|
|
211
|
+
user = await this._usersStore.get(ident.getUser());
|
|
337
212
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
user =
|
|
341
|
-
|
|
342
|
-
else {
|
|
343
|
-
// If an email in profile try to find the ident
|
|
344
|
-
if (ident) {
|
|
345
|
-
user = yield this._usersStore.get(ident.getUser());
|
|
346
|
-
}
|
|
347
|
-
if (!user) {
|
|
348
|
-
// If no user, register a new user automatically
|
|
349
|
-
user = yield this.registerUser(ctx, profile, identId);
|
|
350
|
-
yield this._usersStore.save(user);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (profile.email && !ident) {
|
|
354
|
-
// Save additional email
|
|
355
|
-
ident = this._identsStore.initModel({
|
|
356
|
-
uuid: `${profile.email}_email`,
|
|
357
|
-
provider: "email"
|
|
358
|
-
});
|
|
359
|
-
ident.setUser(user.getUuid());
|
|
360
|
-
yield ident.save();
|
|
213
|
+
if (!user) {
|
|
214
|
+
// If no user, register a new user automatically
|
|
215
|
+
user = await this.registerUser(ctx, profile, identId);
|
|
216
|
+
await this._usersStore.save(user);
|
|
361
217
|
}
|
|
362
|
-
|
|
218
|
+
}
|
|
219
|
+
if (profile.email && !ident) {
|
|
220
|
+
// Save additional email
|
|
363
221
|
ident = this._identsStore.initModel({
|
|
364
|
-
uuid:
|
|
365
|
-
|
|
366
|
-
__tokens: tokens,
|
|
367
|
-
provider
|
|
222
|
+
uuid: `${profile.email}_email`,
|
|
223
|
+
provider: "email"
|
|
368
224
|
});
|
|
369
|
-
ident.setUser(user.
|
|
370
|
-
ident.
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
225
|
+
ident.setUser(user.getUuid());
|
|
226
|
+
await ident.save();
|
|
227
|
+
}
|
|
228
|
+
// Work directly on ident argument
|
|
229
|
+
ident = this._identsStore.initModel({
|
|
230
|
+
uuid: identId,
|
|
231
|
+
profile,
|
|
232
|
+
__tokens: tokens,
|
|
233
|
+
provider
|
|
375
234
|
});
|
|
235
|
+
ident.setUser(user.uuid);
|
|
236
|
+
ident._lastUsed = new Date();
|
|
237
|
+
ident.setType(provider);
|
|
238
|
+
await ident.save();
|
|
239
|
+
ident.__new = true;
|
|
240
|
+
await this.login(ctx, user, ident);
|
|
376
241
|
}
|
|
377
242
|
/**
|
|
378
243
|
* Create a new User with the link ident
|
|
379
244
|
* @param ident
|
|
380
245
|
*/
|
|
381
|
-
createUserWithIdent(provider, identId, profile = {}) {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
user
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
data: data,
|
|
398
|
-
context: ctx,
|
|
399
|
-
identId
|
|
400
|
-
});
|
|
401
|
-
return user;
|
|
246
|
+
async createUserWithIdent(provider, identId, profile = {}) {
|
|
247
|
+
if (await this._identsStore.exists(`${identId}_${provider}`)) {
|
|
248
|
+
throw new Error("Ident is already known");
|
|
249
|
+
}
|
|
250
|
+
let ctx = await this._webda.newContext(new HttpContext("fake", "GET", "/"));
|
|
251
|
+
// Pretend we logged in with the ident
|
|
252
|
+
await this.onIdentLogin(ctx, provider, identId, profile);
|
|
253
|
+
}
|
|
254
|
+
async registerUser(ctx, data, identId, user = this._usersStore.initModel()) {
|
|
255
|
+
user.email = data.email;
|
|
256
|
+
user.locale = ctx.getLocale();
|
|
257
|
+
await this.emitSync("Authentication.Register", {
|
|
258
|
+
user: user,
|
|
259
|
+
data: data,
|
|
260
|
+
context: ctx,
|
|
261
|
+
identId
|
|
402
262
|
});
|
|
263
|
+
return user;
|
|
403
264
|
}
|
|
404
|
-
getPasswordRecoveryInfos(uuid, interval = this.parameters.email.delay) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
};
|
|
423
|
-
});
|
|
265
|
+
async getPasswordRecoveryInfos(uuid, interval = this.parameters.email.delay) {
|
|
266
|
+
const expire = Date.now() + interval;
|
|
267
|
+
let user;
|
|
268
|
+
if (typeof uuid === "string") {
|
|
269
|
+
user = await this._usersStore.get(uuid);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
user = uuid;
|
|
273
|
+
}
|
|
274
|
+
if (!user) {
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
expire: expire,
|
|
279
|
+
// Might want to add more alea not coming from the db to avoid exploitation of stolen db
|
|
280
|
+
token: await this.cryptoService.hmac(user.uuid + expire + user.getPassword()),
|
|
281
|
+
login: user.uuid
|
|
282
|
+
};
|
|
424
283
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
284
|
+
/**
|
|
285
|
+
* Manage password recovery
|
|
286
|
+
* @param ctx
|
|
287
|
+
*/
|
|
288
|
+
async _passwordRecoveryEmail(ctx) {
|
|
289
|
+
let email = ctx.parameter("email");
|
|
290
|
+
let ident = await this._identsStore.get(email + "_email");
|
|
291
|
+
if (!ident) {
|
|
292
|
+
throw 404;
|
|
293
|
+
}
|
|
294
|
+
let user = await this._usersStore.get(ident.getUser());
|
|
295
|
+
// Dont allow to do too many request
|
|
296
|
+
if (!user.lastPasswordRecoveryBefore(Date.now() - this.parameters.email.delay)) {
|
|
297
|
+
throw 429;
|
|
298
|
+
}
|
|
299
|
+
await this._usersStore.patch({
|
|
300
|
+
_lastPasswordRecovery: Date.now(),
|
|
301
|
+
uuid: user.uuid
|
|
442
302
|
});
|
|
303
|
+
await this.sendRecoveryEmail(ctx, user, email);
|
|
443
304
|
}
|
|
444
|
-
_verifyPassword(password, user) {
|
|
445
|
-
|
|
446
|
-
if (this._passwordVerifier) {
|
|
447
|
-
if (!(yield this._passwordVerifier.validate(password, user))) {
|
|
448
|
-
throw 400;
|
|
449
|
-
}
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
let regexp = new RegExp(this.parameters.password.regexp);
|
|
453
|
-
if (regexp.exec(password) === null) {
|
|
305
|
+
async _verifyPassword(password, user) {
|
|
306
|
+
if (this._passwordVerifier) {
|
|
307
|
+
if (!(await this._passwordVerifier.validate(password, user))) {
|
|
454
308
|
throw 400;
|
|
455
309
|
}
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
let regexp = new RegExp(this.parameters.password.regexp);
|
|
313
|
+
if (regexp.exec(password) === null) {
|
|
314
|
+
throw 400;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async _passwordRecovery(ctx) {
|
|
318
|
+
let body = await ctx.getRequestBody();
|
|
319
|
+
if (body.password === undefined ||
|
|
320
|
+
body.login === undefined ||
|
|
321
|
+
body.token === undefined ||
|
|
322
|
+
body.expire === undefined) {
|
|
323
|
+
throw 400;
|
|
324
|
+
}
|
|
325
|
+
let user = await this._usersStore.get(body.login.toLowerCase());
|
|
326
|
+
if (!user) {
|
|
327
|
+
throw 403;
|
|
328
|
+
}
|
|
329
|
+
if (!(await this.cryptoService.hmacVerify(body.login.toLowerCase() + body.expire + user.getPassword(), body.token))) {
|
|
330
|
+
throw 403;
|
|
331
|
+
}
|
|
332
|
+
if (body.expire < Date.now()) {
|
|
333
|
+
throw 410;
|
|
334
|
+
}
|
|
335
|
+
await this._verifyPassword(body.password, user);
|
|
336
|
+
let password = this.hashPassword(body.password);
|
|
337
|
+
await this._usersStore.patch({
|
|
338
|
+
__password: password,
|
|
339
|
+
uuid: body.login.toLowerCase()
|
|
340
|
+
});
|
|
341
|
+
await this.emitSync("Authentication.PasswordUpdate", {
|
|
342
|
+
user,
|
|
343
|
+
password,
|
|
344
|
+
context: ctx
|
|
456
345
|
});
|
|
457
346
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
if (body.token !== this.hashInfo(body.login.toLowerCase() + body.expire + user.getPassword())) {
|
|
472
|
-
throw 403;
|
|
473
|
-
}
|
|
474
|
-
if (body.expire < Date.now()) {
|
|
475
|
-
throw 410;
|
|
476
|
-
}
|
|
477
|
-
yield this._verifyPassword(body.password, user);
|
|
478
|
-
let password = this.hashPassword(body.password);
|
|
479
|
-
yield this._usersStore.patch({
|
|
480
|
-
__password: password,
|
|
481
|
-
uuid: body.login.toLowerCase()
|
|
347
|
+
/**
|
|
348
|
+
* Callback to validate an email address
|
|
349
|
+
* @param ctx
|
|
350
|
+
* @returns
|
|
351
|
+
*/
|
|
352
|
+
async _handleEmailCallback(ctx) {
|
|
353
|
+
if (!ctx.parameter("token")) {
|
|
354
|
+
throw 400;
|
|
355
|
+
}
|
|
356
|
+
if (!(await this.cryptoService.hmacVerify(`${ctx.parameter("email")}_${ctx.parameter("user")}`, ctx.parameter("token")))) {
|
|
357
|
+
ctx.writeHead(302, {
|
|
358
|
+
Location: this.parameters.failureRedirect + "?reason=badToken"
|
|
482
359
|
});
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (ctx.parameter("user") !== ctx.getCurrentUserId() &&
|
|
363
|
+
ctx.getCurrentUserId() !== "" &&
|
|
364
|
+
ctx.getCurrentUserId() !== undefined) {
|
|
365
|
+
ctx.writeHead(302, {
|
|
366
|
+
Location: this.parameters.failureRedirect + "?reason=badUser"
|
|
487
367
|
});
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
492
|
-
if (!ctx.parameter("token")) {
|
|
493
|
-
throw 400;
|
|
494
|
-
}
|
|
495
|
-
let validation = ctx.parameter("token");
|
|
496
|
-
if (validation !== this.generateEmailValidationToken(ctx.parameter("user"), ctx.parameter("email"))) {
|
|
497
|
-
ctx.writeHead(302, {
|
|
498
|
-
Location: this.parameters.failureRedirect + "?reason=badToken"
|
|
499
|
-
});
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
if (ctx.parameter("user") !== ctx.getCurrentUserId() &&
|
|
503
|
-
ctx.getCurrentUserId() !== "" &&
|
|
504
|
-
ctx.getCurrentUserId() !== undefined) {
|
|
505
|
-
ctx.writeHead(302, {
|
|
506
|
-
Location: this.parameters.failureRedirect + "?reason=badUser"
|
|
507
|
-
});
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
if (!ctx.parameter("user")) {
|
|
511
|
-
ctx.writeHead(302, {
|
|
512
|
-
Location: `${this.parameters.registerRedirect}?token=${ctx.parameter("token")}&email=${ctx.parameter("email")}`
|
|
513
|
-
});
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
var uuid = ctx.parameter("email") + "_email";
|
|
517
|
-
let ident = yield this._identsStore.get(uuid);
|
|
518
|
-
// Would mean the ident got delete in the mean time... hyper low likely hood
|
|
519
|
-
if (ident === undefined) {
|
|
520
|
-
ident = this._identsStore.initModel({
|
|
521
|
-
uuid
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
ident._type = "email";
|
|
525
|
-
ident._validation = new Date();
|
|
526
|
-
ident.setUser(ctx.parameter("user"));
|
|
527
|
-
yield ident.save();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (!ctx.parameter("user")) {
|
|
528
371
|
ctx.writeHead(302, {
|
|
529
|
-
Location: this.parameters.
|
|
530
|
-
|
|
372
|
+
Location: `${this.parameters.registerRedirect}?token=${ctx.parameter("token")}&email=${ctx.parameter("email")}`
|
|
373
|
+
});
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const uuid = ctx.parameter("email") + "_email";
|
|
377
|
+
let ident = await this._identsStore.get(uuid);
|
|
378
|
+
// Would mean the ident got delete in the mean time... hyper low likely hood
|
|
379
|
+
if (ident === undefined) {
|
|
380
|
+
ident = this._identsStore.initModel({
|
|
381
|
+
uuid
|
|
531
382
|
});
|
|
383
|
+
}
|
|
384
|
+
ident._type = "email";
|
|
385
|
+
ident._validation = new Date();
|
|
386
|
+
ident.setUser(ctx.parameter("user"));
|
|
387
|
+
await ident.save();
|
|
388
|
+
ctx.writeHead(302, {
|
|
389
|
+
Location: this.parameters.successRedirect + "?validation=email",
|
|
390
|
+
"X-Webda-Authentication": "success"
|
|
532
391
|
});
|
|
533
392
|
}
|
|
534
393
|
/**
|
|
@@ -539,19 +398,17 @@ class Authentication extends service_1.Service {
|
|
|
539
398
|
* @param email
|
|
540
399
|
* @returns
|
|
541
400
|
*/
|
|
542
|
-
sendRecoveryEmail(ctx, user, email) {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return mailer.send(mailOptions);
|
|
554
|
-
});
|
|
401
|
+
async sendRecoveryEmail(ctx, user, email) {
|
|
402
|
+
let infos = await this.getPasswordRecoveryInfos(user);
|
|
403
|
+
const mailer = this.getMailMan();
|
|
404
|
+
let locale = user.locale || ctx.getLocale();
|
|
405
|
+
let mailOptions = {
|
|
406
|
+
to: email,
|
|
407
|
+
locale: locale,
|
|
408
|
+
template: "EMAIL_RECOVERY",
|
|
409
|
+
replacements: { ...this.parameters.email, infos, to: email, context: ctx }
|
|
410
|
+
};
|
|
411
|
+
return mailer.send(mailOptions);
|
|
555
412
|
}
|
|
556
413
|
/**
|
|
557
414
|
* Send an email to validate the user email by sending a unique link to
|
|
@@ -561,33 +418,26 @@ class Authentication extends service_1.Service {
|
|
|
561
418
|
* @param email
|
|
562
419
|
* @returns
|
|
563
420
|
*/
|
|
564
|
-
sendValidationEmail(ctx, email) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
* Create a SHA256 of the info
|
|
585
|
-
*
|
|
586
|
-
* @param info to hash
|
|
587
|
-
*/
|
|
588
|
-
hashInfo(info) {
|
|
589
|
-
var hash = crypto.createHash("sha256");
|
|
590
|
-
return hash.update(info).digest("hex");
|
|
421
|
+
async sendValidationEmail(ctx, email) {
|
|
422
|
+
const mailer = this.getMailMan();
|
|
423
|
+
let replacements = {
|
|
424
|
+
...this.parameters.email,
|
|
425
|
+
context: ctx,
|
|
426
|
+
url: ctx
|
|
427
|
+
.getHttpContext()
|
|
428
|
+
.getAbsoluteUrl(`${this.parameters.url}/email/callback?email=${email}&token=${await this.generateEmailValidationToken(ctx.getCurrentUserId(), email)}`)
|
|
429
|
+
};
|
|
430
|
+
let userId = ctx.getCurrentUserId();
|
|
431
|
+
if (userId && userId.length > 0) {
|
|
432
|
+
replacements.url += "&user=" + userId;
|
|
433
|
+
}
|
|
434
|
+
let mailOptions = {
|
|
435
|
+
to: email,
|
|
436
|
+
locale: ctx.getLocale(),
|
|
437
|
+
template: "EMAIL_REGISTER",
|
|
438
|
+
replacements: replacements
|
|
439
|
+
};
|
|
440
|
+
return mailer.send(mailOptions);
|
|
591
441
|
}
|
|
592
442
|
/**
|
|
593
443
|
* Check the password match the stored hash
|
|
@@ -608,13 +458,11 @@ class Authentication extends service_1.Service {
|
|
|
608
458
|
/**
|
|
609
459
|
* Logout user
|
|
610
460
|
*/
|
|
611
|
-
logout(ctx) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
context: ctx
|
|
615
|
-
});
|
|
616
|
-
ctx.getSession().destroy();
|
|
461
|
+
async logout(ctx) {
|
|
462
|
+
await this.emitSync("Authentication.Logout", {
|
|
463
|
+
context: ctx
|
|
617
464
|
});
|
|
465
|
+
ctx.newSession();
|
|
618
466
|
}
|
|
619
467
|
/**
|
|
620
468
|
* Login a user
|
|
@@ -624,25 +472,23 @@ class Authentication extends service_1.Service {
|
|
|
624
472
|
* @param ident
|
|
625
473
|
* @returns
|
|
626
474
|
*/
|
|
627
|
-
login(ctx, user, ident) {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
return this.emitSync("Authentication.Login", event);
|
|
645
|
-
});
|
|
475
|
+
async login(ctx, user, ident) {
|
|
476
|
+
const event = {
|
|
477
|
+
context: ctx,
|
|
478
|
+
userId: "",
|
|
479
|
+
identId: ident.uuid,
|
|
480
|
+
ident
|
|
481
|
+
};
|
|
482
|
+
if (typeof user == "object") {
|
|
483
|
+
event.userId = user.uuid;
|
|
484
|
+
event.user = user;
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
event.userId = user;
|
|
488
|
+
}
|
|
489
|
+
event.context = ctx;
|
|
490
|
+
ctx.getSession().login(event.userId, event.identId);
|
|
491
|
+
return this.emitSync("Authentication.Login", event);
|
|
646
492
|
}
|
|
647
493
|
getMailMan() {
|
|
648
494
|
return this.getService(this.parameters.email.mailer ? this.parameters.email.mailer : "Mailer");
|
|
@@ -653,40 +499,37 @@ class Authentication extends service_1.Service {
|
|
|
653
499
|
* @param ctx
|
|
654
500
|
* @param ident
|
|
655
501
|
*/
|
|
656
|
-
handleLogin(ctx, ident) {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if (!ctx.isEnded()) {
|
|
686
|
-
throw 403;
|
|
687
|
-
}
|
|
502
|
+
async handleLogin(ctx, ident) {
|
|
503
|
+
let updates = {};
|
|
504
|
+
let user = await this._usersStore.get(ident.getUser());
|
|
505
|
+
// Check password
|
|
506
|
+
if (this.checkPassword(user.getPassword(), (await ctx.getRequestBody()).password)) {
|
|
507
|
+
if (ident._failedLogin > 0) {
|
|
508
|
+
ident._failedLogin = 0;
|
|
509
|
+
}
|
|
510
|
+
updates._lastUsed = new Date();
|
|
511
|
+
updates._failedLogin = 0;
|
|
512
|
+
updates.uuid = ident.uuid;
|
|
513
|
+
await this._identsStore.patch(updates);
|
|
514
|
+
await this.login(ctx, ident.getUser(), ident);
|
|
515
|
+
ctx.write(user);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
await this.emitSync("Authentication.LoginFailed", {
|
|
519
|
+
user,
|
|
520
|
+
context: ctx
|
|
521
|
+
});
|
|
522
|
+
ident._failedLogin ?? (ident._failedLogin = 0);
|
|
523
|
+
updates._failedLogin = ident._failedLogin + 1;
|
|
524
|
+
updates._lastFailedLogin = new Date();
|
|
525
|
+
updates.uuid = ident.uuid;
|
|
526
|
+
// Swalow exeception issue to double check !
|
|
527
|
+
await this._identsStore.patch(updates);
|
|
528
|
+
// Allows to auto redirect user to a oauth if needed
|
|
529
|
+
if (!ctx.isEnded()) {
|
|
530
|
+
throw 403;
|
|
688
531
|
}
|
|
689
|
-
}
|
|
532
|
+
}
|
|
690
533
|
}
|
|
691
534
|
/**
|
|
692
535
|
* Handle the POST /auth/email
|
|
@@ -694,95 +537,220 @@ class Authentication extends service_1.Service {
|
|
|
694
537
|
* @param ctx
|
|
695
538
|
* @returns
|
|
696
539
|
*/
|
|
697
|
-
_handleEmail(ctx) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
540
|
+
async _handleEmail(ctx) {
|
|
541
|
+
// If called while logged in reject
|
|
542
|
+
if (ctx.getCurrentUserId() !== undefined) {
|
|
543
|
+
throw 410;
|
|
544
|
+
}
|
|
545
|
+
let body = await ctx.getRequestBody();
|
|
546
|
+
if (body.login === undefined) {
|
|
547
|
+
throw 400;
|
|
548
|
+
}
|
|
549
|
+
const mailConfig = this.parameters.email;
|
|
550
|
+
const uuid = body.login.toLowerCase() + "_email";
|
|
551
|
+
let ident = await this._identsStore.get(uuid);
|
|
552
|
+
if (ident !== undefined && ident.getUser() !== undefined) {
|
|
553
|
+
// Register on an known user
|
|
554
|
+
if (!body.register) {
|
|
555
|
+
await this.handleLogin(ctx, ident);
|
|
556
|
+
return;
|
|
702
557
|
}
|
|
703
|
-
|
|
704
|
-
if (
|
|
705
|
-
throw
|
|
558
|
+
// If register on a validate email
|
|
559
|
+
if (ident._validation !== undefined) {
|
|
560
|
+
throw 409;
|
|
706
561
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
562
|
+
}
|
|
563
|
+
// TODO Handle add of email on authenticated user
|
|
564
|
+
const email = body.login.toLowerCase();
|
|
565
|
+
// Read the form
|
|
566
|
+
if (body.register) {
|
|
567
|
+
let validation = undefined;
|
|
568
|
+
// Need to check email before creation
|
|
569
|
+
if (!mailConfig.postValidation) {
|
|
570
|
+
if (body.token && (await this.cryptoService.hmacVerify(`${email}_${ctx.getCurrentUserId()}`, body.token))) {
|
|
571
|
+
validation = new Date();
|
|
715
572
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
573
|
+
else {
|
|
574
|
+
ctx.write({});
|
|
575
|
+
// token is undefined send an email
|
|
576
|
+
return this.sendValidationEmail(ctx, email);
|
|
719
577
|
}
|
|
720
578
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
// Read the form
|
|
724
|
-
if (body.register) {
|
|
725
|
-
var validation = undefined;
|
|
726
|
-
// Need to check email before creation
|
|
727
|
-
if (!mailConfig.postValidation) {
|
|
728
|
-
if (body.token == this.generateEmailValidationToken(ctx.getCurrentUserId(), email)) {
|
|
729
|
-
validation = new Date();
|
|
730
|
-
}
|
|
731
|
-
else {
|
|
732
|
-
ctx.write({});
|
|
733
|
-
// token is undefined send an email
|
|
734
|
-
return this.sendValidationEmail(ctx, email);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
if (!body.password) {
|
|
738
|
-
throw 400;
|
|
739
|
-
}
|
|
740
|
-
// Store with a _
|
|
741
|
-
let __password = this.hashPassword(body.password);
|
|
742
|
-
yield this._verifyPassword(body.password);
|
|
743
|
-
// Remove useless attributes
|
|
744
|
-
delete body.password;
|
|
745
|
-
delete body.register;
|
|
746
|
-
delete body.token;
|
|
747
|
-
let user = yield this.registerUser(ctx, {}, uuid, Object.assign(Object.assign({}, body), { __password }));
|
|
748
|
-
yield this.emitSync("Authentication.PasswordCreate", {
|
|
749
|
-
user,
|
|
750
|
-
password: __password,
|
|
751
|
-
context: ctx
|
|
752
|
-
});
|
|
753
|
-
user = yield this._usersStore.save(user);
|
|
754
|
-
var newIdent = this._identsStore.initModel({
|
|
755
|
-
uuid: uuid,
|
|
756
|
-
_type: "email",
|
|
757
|
-
email: email
|
|
758
|
-
});
|
|
759
|
-
newIdent.setUser(user.uuid);
|
|
760
|
-
if (validation) {
|
|
761
|
-
newIdent._validation = validation;
|
|
762
|
-
}
|
|
763
|
-
else if (!mailConfig.skipEmailValidation) {
|
|
764
|
-
newIdent._lastValidationEmail = Date.now();
|
|
765
|
-
}
|
|
766
|
-
ident = yield newIdent.save();
|
|
767
|
-
yield this.login(ctx, user, ident);
|
|
768
|
-
ctx.write(user);
|
|
769
|
-
if (!validation && !mailConfig.skipEmailValidation) {
|
|
770
|
-
yield this.sendValidationEmail(ctx, email);
|
|
771
|
-
}
|
|
772
|
-
return;
|
|
579
|
+
if (!body.password) {
|
|
580
|
+
throw 400;
|
|
773
581
|
}
|
|
774
|
-
|
|
775
|
-
|
|
582
|
+
// Store with a _
|
|
583
|
+
let __password = this.hashPassword(body.password);
|
|
584
|
+
await this._verifyPassword(body.password);
|
|
585
|
+
// Remove useless attributes
|
|
586
|
+
delete body.password;
|
|
587
|
+
delete body.register;
|
|
588
|
+
delete body.token;
|
|
589
|
+
let user = await this.registerUser(ctx, {}, uuid, { ...body, __password });
|
|
590
|
+
await this.emitSync("Authentication.PasswordCreate", {
|
|
591
|
+
user,
|
|
592
|
+
password: __password,
|
|
593
|
+
context: ctx
|
|
594
|
+
});
|
|
595
|
+
user = await this._usersStore.save(user);
|
|
596
|
+
const newIdent = this._identsStore.initModel({
|
|
597
|
+
uuid: uuid,
|
|
598
|
+
_type: "email",
|
|
599
|
+
email: email
|
|
600
|
+
});
|
|
601
|
+
newIdent.setUser(user.uuid);
|
|
602
|
+
if (validation) {
|
|
603
|
+
newIdent._validation = validation;
|
|
604
|
+
}
|
|
605
|
+
else if (!mailConfig.skipEmailValidation) {
|
|
606
|
+
newIdent._lastValidationEmail = Date.now();
|
|
607
|
+
}
|
|
608
|
+
ident = await newIdent.save();
|
|
609
|
+
await this.login(ctx, user, ident);
|
|
610
|
+
ctx.write(user);
|
|
611
|
+
if (!validation && !mailConfig.skipEmailValidation) {
|
|
612
|
+
await this.sendValidationEmail(ctx, email);
|
|
613
|
+
}
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
throw 404;
|
|
776
617
|
}
|
|
777
|
-
generateEmailValidationToken(user, email) {
|
|
778
|
-
return this.
|
|
618
|
+
async generateEmailValidationToken(user, email) {
|
|
619
|
+
return this.cryptoService.hmac(email + "_" + user);
|
|
779
620
|
}
|
|
780
621
|
}
|
|
781
622
|
__decorate([
|
|
782
|
-
|
|
623
|
+
Inject("identStore", "idents")
|
|
783
624
|
], Authentication.prototype, "_identsStore", void 0);
|
|
784
625
|
__decorate([
|
|
785
|
-
|
|
626
|
+
Inject("userStore", "users")
|
|
786
627
|
], Authentication.prototype, "_usersStore", void 0);
|
|
787
|
-
|
|
628
|
+
__decorate([
|
|
629
|
+
Inject("CryptoService")
|
|
630
|
+
], Authentication.prototype, "cryptoService", void 0);
|
|
631
|
+
__decorate([
|
|
632
|
+
Route("./email/{email}/validate", ["GET"], false, {
|
|
633
|
+
get: {
|
|
634
|
+
description: "The email validation process will be start",
|
|
635
|
+
summary: "Restart email validation",
|
|
636
|
+
operationId: "startEmailRecovery",
|
|
637
|
+
responses: {
|
|
638
|
+
"204": {
|
|
639
|
+
description: ""
|
|
640
|
+
},
|
|
641
|
+
"409": {
|
|
642
|
+
description: "Email already verified for another user"
|
|
643
|
+
},
|
|
644
|
+
"412": {
|
|
645
|
+
description: "Email already verified for current user"
|
|
646
|
+
},
|
|
647
|
+
"429": {
|
|
648
|
+
description: "Validation has been initiated in the last 4 hours"
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
})
|
|
653
|
+
], Authentication.prototype, "_sendEmailValidation", null);
|
|
654
|
+
__decorate([
|
|
655
|
+
Route("./me", ["GET"], false, {
|
|
656
|
+
get: {
|
|
657
|
+
description: "Retrieve the current user from the session",
|
|
658
|
+
summary: "Get current user",
|
|
659
|
+
operationId: "getCurrentUser"
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
], Authentication.prototype, "_getMe", null);
|
|
663
|
+
__decorate([
|
|
664
|
+
Route(".", ["GET", "DELETE"], false, {
|
|
665
|
+
get: {
|
|
666
|
+
description: "Retrieve the list of available authentication",
|
|
667
|
+
summary: "Get available auths",
|
|
668
|
+
operationId: `getAuthenticationMethods`,
|
|
669
|
+
responses: {
|
|
670
|
+
"200": {
|
|
671
|
+
description: "List of authentication"
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
delete: {
|
|
676
|
+
description: "Logout current user",
|
|
677
|
+
summary: "Logout",
|
|
678
|
+
operationId: `logout`,
|
|
679
|
+
responses: {
|
|
680
|
+
"200": {}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
})
|
|
684
|
+
], Authentication.prototype, "_listAuthentications", null);
|
|
685
|
+
__decorate([
|
|
686
|
+
Route("./email/{email}/recover", ["GET"], false, {
|
|
687
|
+
get: {
|
|
688
|
+
description: "The password reset process will be start",
|
|
689
|
+
summary: "Start password recovery",
|
|
690
|
+
operationId: "startEmailRecovery",
|
|
691
|
+
responses: {
|
|
692
|
+
"204": {
|
|
693
|
+
description: ""
|
|
694
|
+
},
|
|
695
|
+
"404": {
|
|
696
|
+
description: "Email does not exist"
|
|
697
|
+
},
|
|
698
|
+
"429": {
|
|
699
|
+
description: "Recovery has been initiated in the last 4 hours"
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
})
|
|
704
|
+
], Authentication.prototype, "_passwordRecoveryEmail", null);
|
|
705
|
+
__decorate([
|
|
706
|
+
Route("./email/passwordRecovery", ["POST"], false, {
|
|
707
|
+
post: {
|
|
708
|
+
schemas: {
|
|
709
|
+
input: {
|
|
710
|
+
type: "object",
|
|
711
|
+
properties: {
|
|
712
|
+
token: {
|
|
713
|
+
type: "string"
|
|
714
|
+
},
|
|
715
|
+
expire: {
|
|
716
|
+
type: "number"
|
|
717
|
+
},
|
|
718
|
+
password: {
|
|
719
|
+
type: "string"
|
|
720
|
+
},
|
|
721
|
+
login: {
|
|
722
|
+
type: "string"
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
description: "Reinit the password if we have the right token, expire",
|
|
728
|
+
summary: "Reinit password",
|
|
729
|
+
operationId: "reinitPassword",
|
|
730
|
+
responses: {
|
|
731
|
+
"204": {
|
|
732
|
+
description: ""
|
|
733
|
+
},
|
|
734
|
+
"403": {
|
|
735
|
+
description: "Wrong Token"
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
})
|
|
740
|
+
], Authentication.prototype, "_passwordRecovery", null);
|
|
741
|
+
__decorate([
|
|
742
|
+
Route("./email/callback{?email,token,user}", ["GET"], false, {
|
|
743
|
+
hidden: true
|
|
744
|
+
})
|
|
745
|
+
], Authentication.prototype, "_handleEmailCallback", null);
|
|
746
|
+
__decorate([
|
|
747
|
+
Route("./email", ["POST"], false, {
|
|
748
|
+
post: {
|
|
749
|
+
description: "Authenticate with an email and password",
|
|
750
|
+
summary: "Authenticate with email",
|
|
751
|
+
operationId: `authWithEmail`
|
|
752
|
+
}
|
|
753
|
+
})
|
|
754
|
+
], Authentication.prototype, "_handleEmail", null);
|
|
755
|
+
export { Authentication };
|
|
788
756
|
//# sourceMappingURL=authentication.js.map
|