@social-mail/social-mail-web-server 1.4.829 → 1.4.830
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/dist/server/model/entities/LoginSession.d.ts +3 -2
- package/dist/server/model/entities/LoginSession.d.ts.map +1 -1
- package/dist/server/model/entities/LoginSession.js +8 -16
- package/dist/server/model/entities/LoginSession.js.map +1 -1
- package/dist/server/model/entities/UserAuthFactor.d.ts +3 -0
- package/dist/server/model/entities/UserAuthFactor.d.ts.map +1 -1
- package/dist/server/model/entities/UserAuthFactor.js +9 -0
- package/dist/server/model/entities/UserAuthFactor.js.map +1 -1
- package/dist/server/model/entities/VerificationToken.d.ts +6 -0
- package/dist/server/model/entities/VerificationToken.d.ts.map +1 -1
- package/dist/server/model/entities/VerificationToken.js +9 -0
- package/dist/server/model/entities/VerificationToken.js.map +1 -1
- package/dist/server/model/events/LoginSessionEvents.d.ts.map +1 -1
- package/dist/server/model/events/LoginSessionEvents.js +5 -6
- package/dist/server/model/events/LoginSessionEvents.js.map +1 -1
- package/dist/server/model/events/UserAuthFactorEvents.d.ts.map +1 -1
- package/dist/server/model/events/UserAuthFactorEvents.js +5 -6
- package/dist/server/model/events/UserAuthFactorEvents.js.map +1 -1
- package/dist/server/services/external-otp-in/ExternalOtpInService.d.ts +6 -2
- package/dist/server/services/external-otp-in/ExternalOtpInService.d.ts.map +1 -1
- package/dist/server/services/external-otp-in/ExternalOtpInService.js +33 -5
- package/dist/server/services/external-otp-in/ExternalOtpInService.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/server/model/entities/LoginSession.ts +9 -14
- package/src/server/model/entities/UserAuthFactor.ts +10 -0
- package/src/server/model/entities/VerificationToken.ts +10 -5
- package/src/server/model/events/LoginSessionEvents.ts +5 -6
- package/src/server/model/events/UserAuthFactorEvents.ts +5 -6
- package/src/server/services/external-otp-in/ExternalOtpInService.ts +34 -5
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import type { AppFileVersion } from "./AppFile.js";
|
|
|
7
7
|
import Index from "@entity-access/entity-access/dist/decorators/Index.js";
|
|
8
8
|
import GraphService from "@entity-access/server-pages/dist/services/GraphService.js";
|
|
9
9
|
import { IgnoreJsonProperty, JsonProperty } from "@entity-access/server-pages/dist/services/ModelService.js";
|
|
10
|
+
import VerificationToken from "./VerificationToken.js";
|
|
10
11
|
|
|
11
12
|
const loginSessionStatuses = ["created", "change-password", "totp"] as const;
|
|
12
13
|
export type loginStatusType = typeof loginSessionStatuses[number];
|
|
@@ -20,15 +21,6 @@ export type loginStatusType = typeof loginSessionStatuses[number];
|
|
|
20
21
|
],
|
|
21
22
|
filter: (x) => x.invalid === false && x.deviceTokenType !== null
|
|
22
23
|
})
|
|
23
|
-
@Index({
|
|
24
|
-
name: "IX_LoginSessions_Phone_Codes",
|
|
25
|
-
columns: [
|
|
26
|
-
{ name: (x) => x.userID, descending: false },
|
|
27
|
-
{ name: (x) => x.smsToken, descending: false }
|
|
28
|
-
],
|
|
29
|
-
unique: true,
|
|
30
|
-
filter: (x) => x.smsToken !== null
|
|
31
|
-
})
|
|
32
24
|
export default class LoginSession {
|
|
33
25
|
|
|
34
26
|
@Column({ key: true, generated: "identity"})
|
|
@@ -64,8 +56,12 @@ export default class LoginSession {
|
|
|
64
56
|
@Column({ dataType: "AsciiChar", length: 50, nullable: true})
|
|
65
57
|
public deviceTokenType: string;
|
|
66
58
|
|
|
67
|
-
@Column({ dataType: "
|
|
68
|
-
|
|
59
|
+
@Column({ dataType: "BigInt", nullable: true })
|
|
60
|
+
@RelateTo(VerificationToken, {
|
|
61
|
+
property: (x) => x.verificationToken,
|
|
62
|
+
inverseProperty: (x) => x.loginSessions
|
|
63
|
+
})
|
|
64
|
+
public verificationID: number;
|
|
69
65
|
|
|
70
66
|
/**
|
|
71
67
|
* This will not be saved into database
|
|
@@ -98,13 +94,12 @@ export default class LoginSession {
|
|
|
98
94
|
@JsonProperty({ help: "One Time Password"})
|
|
99
95
|
public oneTimePassword: string;
|
|
100
96
|
|
|
101
|
-
@JsonProperty({ help: "SMS URL to Display"})
|
|
102
|
-
public smsConfig: any;
|
|
103
|
-
|
|
104
97
|
public user: User;
|
|
105
98
|
|
|
106
99
|
public versions: AppFileVersion[];
|
|
107
100
|
|
|
101
|
+
public verificationToken: VerificationToken;
|
|
102
|
+
|
|
108
103
|
[GraphService.appendToGraph]() {
|
|
109
104
|
delete this.deviceToken;
|
|
110
105
|
delete this.deviceTokenType;
|
|
@@ -8,6 +8,7 @@ import IncomingSmsSource from "./IncomingSmsSource.js";
|
|
|
8
8
|
import CheckConstraint from "@entity-access/entity-access/dist/decorators/CheckConstraint.js";
|
|
9
9
|
import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
|
|
10
10
|
import Index from "@entity-access/entity-access/dist/decorators/Index.js";
|
|
11
|
+
import VerificationToken from "./VerificationToken.js";
|
|
11
12
|
|
|
12
13
|
const authMethods = ["totp", "hotp", "fido2", "one-time", "otp", "otp-in"] as const;
|
|
13
14
|
export type authMethodTypes = typeof authMethods[number];
|
|
@@ -50,6 +51,13 @@ export default class UserAuthFactor {
|
|
|
50
51
|
@Column({ dataType: "Char", length: 20, nullable: true })
|
|
51
52
|
isdCode: string;
|
|
52
53
|
|
|
54
|
+
@Column({ dataType: "BigInt", nullable: true })
|
|
55
|
+
@RelateTo(VerificationToken, {
|
|
56
|
+
property: (x) => x.verificationToken,
|
|
57
|
+
inverseProperty: (x) => x.authFactors
|
|
58
|
+
})
|
|
59
|
+
public verificationID: number;
|
|
60
|
+
|
|
53
61
|
@Column({ dataType: "Boolean"})
|
|
54
62
|
verified: boolean;
|
|
55
63
|
|
|
@@ -70,4 +78,6 @@ export default class UserAuthFactor {
|
|
|
70
78
|
@JsonProperty()
|
|
71
79
|
smsConfig: string;
|
|
72
80
|
|
|
81
|
+
public verificationToken: VerificationToken;
|
|
82
|
+
|
|
73
83
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import Column from "@entity-access/entity-access/dist/decorators/Column.js";
|
|
2
|
-
import Index from "@entity-access/entity-access/dist/decorators/Index.js";
|
|
3
2
|
import Table from "@entity-access/entity-access/dist/decorators/Table.js";
|
|
4
|
-
import { ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
|
|
5
3
|
import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
|
|
6
4
|
import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
|
|
7
|
-
import GraphService from "@entity-access/server-pages/dist/services/GraphService.js";
|
|
8
|
-
import SignerService from "../../services/SignerService.js";
|
|
9
|
-
import Page from "@entity-access/server-pages/dist/Page.js";
|
|
10
5
|
import { RelateTo } from "@entity-access/entity-access/dist/decorators/Relate.js";
|
|
6
|
+
import type LoginSession from "./LoginSession.js";
|
|
7
|
+
import { JsonProperty } from "@entity-access/server-pages/dist/services/ModelService.js";
|
|
8
|
+
import type UserAuthFactor from "./UserAuthFactor.js";
|
|
11
9
|
|
|
12
10
|
@Table("VerificationTokens")
|
|
13
11
|
export default class VerificationToken {
|
|
@@ -15,6 +13,9 @@ export default class VerificationToken {
|
|
|
15
13
|
@Column({ dataType: "BigInt", key: true, generated: "identity"})
|
|
16
14
|
verificationID: number;
|
|
17
15
|
|
|
16
|
+
@Column({ dataType: "Char", length: 200, nullable: true })
|
|
17
|
+
externalID: string;
|
|
18
|
+
|
|
18
19
|
@Column({ default: () => Sql.date.now()})
|
|
19
20
|
dateCreated: DateTime;
|
|
20
21
|
|
|
@@ -33,7 +34,11 @@ export default class VerificationToken {
|
|
|
33
34
|
@Column({ dataType: "Char", length: 50, nullable: true })
|
|
34
35
|
ipAddress: string;
|
|
35
36
|
addresses: VerificationTokenAddress[];
|
|
37
|
+
loginSessions: LoginSession[];
|
|
38
|
+
authFactors: UserAuthFactor[];
|
|
36
39
|
|
|
40
|
+
@JsonProperty({})
|
|
41
|
+
smsConfig: any;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
@Table("VerificationTokenAddresses")
|
|
@@ -138,9 +138,9 @@ export default class LoginSessionEvents extends EntityEvents<LoginSession> {
|
|
|
138
138
|
|
|
139
139
|
if (otpIn.length) {
|
|
140
140
|
const idsCodes = otpIn.map((x) => x.phoneNumber );
|
|
141
|
-
const
|
|
142
|
-
entity.
|
|
143
|
-
entity.
|
|
141
|
+
const v = await ServiceProvider.resolve(this, ExternalOtpInService).create(idsCodes);
|
|
142
|
+
entity.verificationID = v.verificationID;
|
|
143
|
+
entity.verificationToken = v;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
return;
|
|
@@ -189,10 +189,9 @@ export default class LoginSessionEvents extends EntityEvents<LoginSession> {
|
|
|
189
189
|
async beforeUpdate(entity: LoginSession, entry: ChangeEntry<LoginSession>) {
|
|
190
190
|
|
|
191
191
|
if (entry.isModified("dateUpdated")) {
|
|
192
|
-
if(entity.
|
|
193
|
-
const [id, accessCode] = entity.smsToken.split(":");
|
|
192
|
+
if(entity.verificationID) {
|
|
194
193
|
const eis = ServiceProvider.resolve(this, ExternalOtpInService);
|
|
195
|
-
const { success } = await eis.get(
|
|
194
|
+
const { success } = await eis.get(entity.verificationID);
|
|
196
195
|
if (success) {
|
|
197
196
|
entity.status = "created";
|
|
198
197
|
entity.invalid = false;
|
|
@@ -58,10 +58,9 @@ export default class UserAuthFactorEvents extends AuthenticatedEvents<UserAuthFa
|
|
|
58
58
|
|
|
59
59
|
const phones = await db.userAuthFactors.where(entity, (p) => (x) => x.userID === p.userID && x.method === "otp-in").toArray();
|
|
60
60
|
const phoneNumbers = phones.map((x) => x.phoneNumber);
|
|
61
|
-
const
|
|
62
|
-
entity.
|
|
63
|
-
entity.
|
|
64
|
-
entity.hint = smsConfig.id;
|
|
61
|
+
const v = await ServiceProvider.resolve(this, ExternalOtpInService).create(phoneNumbers);
|
|
62
|
+
entity.verificationID = v.verificationID;
|
|
63
|
+
entity.verificationToken = v;
|
|
65
64
|
return;
|
|
66
65
|
}
|
|
67
66
|
|
|
@@ -102,10 +101,10 @@ export default class UserAuthFactorEvents extends AuthenticatedEvents<UserAuthFa
|
|
|
102
101
|
}
|
|
103
102
|
if (!entity.verified) {
|
|
104
103
|
|
|
105
|
-
if (
|
|
104
|
+
if (entity.verificationID) {
|
|
106
105
|
|
|
107
106
|
const eois = ServiceProvider.resolve(this, ExternalOtpInService);
|
|
108
|
-
const result = await eois.get(entity.
|
|
107
|
+
const result = await eois.get(entity.verificationID);
|
|
109
108
|
if (result.success) {
|
|
110
109
|
entity.verified = true;
|
|
111
110
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
|
|
1
|
+
import Inject, { RegisterScoped, RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
|
|
2
2
|
import { globalEnv } from "../../../common/globalEnv.js";
|
|
3
|
+
import SocialMailContext from "../../model/SocialMailContext.js";
|
|
4
|
+
import CryptoService from "../CryptoService.js";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
|
|
3
7
|
|
|
4
8
|
const headers = {
|
|
5
9
|
authorization: `basic ${Buffer.from(`${globalEnv.otpIn.key}:${globalEnv.otpIn.secret}`).toString("base64")}`
|
|
@@ -10,9 +14,15 @@ const postHeaders = {
|
|
|
10
14
|
"content-type": "application/json",
|
|
11
15
|
};
|
|
12
16
|
|
|
13
|
-
@
|
|
17
|
+
@RegisterScoped
|
|
14
18
|
export default class ExternalOtpInService {
|
|
15
19
|
|
|
20
|
+
@Inject
|
|
21
|
+
db: SocialMailContext;
|
|
22
|
+
|
|
23
|
+
@Inject
|
|
24
|
+
cryptoService: CryptoService;
|
|
25
|
+
|
|
16
26
|
async create(phoneNumbers: string[]) {
|
|
17
27
|
const rs = await fetch(`https://${globalEnv.otpIn.host}/api/otp-in/create`, {
|
|
18
28
|
method: "POST",
|
|
@@ -21,11 +31,30 @@ export default class ExternalOtpInService {
|
|
|
21
31
|
phoneNumbers
|
|
22
32
|
})
|
|
23
33
|
});
|
|
24
|
-
|
|
34
|
+
const result = await rs.json();
|
|
35
|
+
|
|
36
|
+
const dateCreated = DateTime.now;
|
|
37
|
+
const expiry = dateCreated.addMinutes(15);
|
|
38
|
+
|
|
39
|
+
const { accessCode } = result;
|
|
40
|
+
|
|
41
|
+
// create hash
|
|
42
|
+
const v = await this.db.verificationTokens.statements.insert({
|
|
43
|
+
externalID: result.id,
|
|
44
|
+
accessCode,
|
|
45
|
+
dateCreated,
|
|
46
|
+
expiry,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
result.id = v.verificationID.toString();
|
|
51
|
+
v.smsConfig = result;
|
|
52
|
+
return v;
|
|
25
53
|
}
|
|
26
54
|
|
|
27
|
-
async get(
|
|
28
|
-
const
|
|
55
|
+
async get(verificationID) {
|
|
56
|
+
const v = await this.db.verificationTokens.statements.select({} , { verificationID });
|
|
57
|
+
const rs = await fetch(`https://${globalEnv.otpIn.host}/api/otp-in/get/${v.externalID}/${v.accessCode}`, {
|
|
29
58
|
method: "GET",
|
|
30
59
|
headers
|
|
31
60
|
});
|