pico-auth 0.0.3 → 0.0.4
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/pico-auth.d.ts +16 -1
- package/dist/pico-auth.esm.js +53 -66
- package/dist/pico-auth.esm.min.js +1 -1
- package/dist/pico-auth.umd.js +53 -66
- package/dist/pico-auth.umd.min.js +1 -1
- package/package.json +4 -3
package/dist/pico-auth.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
declare module "core/auth" {
|
|
2
|
+
/**
|
|
3
|
+
* When mfaToken is provided
|
|
4
|
+
*/
|
|
5
|
+
export const authenticate: (login: string, password: string, mfaToken: string, impersonateEntity: string, userProvider: any, impersonateProvider: any) => Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
8
|
+
*/
|
|
9
|
+
export const mfaRegister: (appName: string, login: string, userProvider: any) => Promise<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
12
|
+
*/
|
|
13
|
+
export const mfaVerify: (login: string, mfaToken: string, userProvider: any) => Promise<boolean>;
|
|
14
|
+
export const mfaEnabled: (login: string, userProvider: any) => Promise<any>;
|
|
15
|
+
}
|
|
1
16
|
declare module "pico-auth" {
|
|
2
|
-
export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "
|
|
17
|
+
export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "core/auth";
|
|
3
18
|
}
|
package/dist/pico-auth.esm.js
CHANGED
|
@@ -1,47 +1,42 @@
|
|
|
1
1
|
const speakeasy = require('speakeasy');
|
|
2
2
|
const qrcode = require('qrcode');
|
|
3
3
|
const md5 = require("md5");
|
|
4
|
-
|
|
4
|
+
const jwt = require('jsonwebtoken');
|
|
5
5
|
/**
|
|
6
6
|
* When mfaToken is provided
|
|
7
7
|
*/
|
|
8
8
|
const authenticate = async (login, password, mfaToken, impersonateEntity, userProvider, impersonateProvider) => {
|
|
9
|
+
var _a, _b, _c;
|
|
9
10
|
let user = await userProvider.getUser(login);
|
|
10
|
-
|
|
11
|
-
if(user.mfa?.enabled){
|
|
11
|
+
if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
12
12
|
// Validate the token against the user's saved secret
|
|
13
13
|
const validated = speakeasy.totp.verify({
|
|
14
|
-
secret: user.mfa
|
|
14
|
+
secret: (_c = (_b = user.mfa) === null || _b === void 0 ? void 0 : _b.secret) === null || _c === void 0 ? void 0 : _c.actual,
|
|
15
15
|
encoding: 'base32',
|
|
16
16
|
mfaToken,
|
|
17
17
|
window: 1, // Adjust window size if tokens have a margin of error
|
|
18
18
|
});
|
|
19
|
-
if(!validated)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if(md5(password||'') == user.password){
|
|
19
|
+
if (!validated)
|
|
20
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
21
|
+
}
|
|
22
|
+
if (md5(password || '') == user.password) {
|
|
23
23
|
// check if impersonate mode - this is not yet implemented fully just copy pasta from GRM project
|
|
24
24
|
const target = impersonateEntity; // either target user login or @organizationId
|
|
25
25
|
const originalUser = user;
|
|
26
|
-
|
|
27
|
-
if(target){
|
|
28
|
-
|
|
26
|
+
if (target) {
|
|
29
27
|
// impersonate flow
|
|
30
28
|
let mayImpersonate = false;
|
|
31
|
-
|
|
32
29
|
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
33
|
-
if(target.startsWith("@")){
|
|
30
|
+
if (target.startsWith("@")) {
|
|
34
31
|
// only organization impersonation
|
|
35
32
|
// check requesting user has global admin
|
|
36
33
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
37
34
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
38
35
|
// mayImpersonate = true;
|
|
39
36
|
// todo check org exists
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
37
|
+
if (!mayImpersonate) {
|
|
38
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
39
|
+
}
|
|
45
40
|
// switch original user organization_id
|
|
46
41
|
impersonateProvider.impersonate(user, target);
|
|
47
42
|
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
@@ -52,103 +47,95 @@ const authenticate = async (login, password, mfaToken, impersonateEntity, userPr
|
|
|
52
47
|
else {
|
|
53
48
|
// full user impersonation
|
|
54
49
|
// load target user
|
|
55
|
-
const targetUser = await userProvider.getUser(target);
|
|
56
|
-
|
|
50
|
+
const targetUser = await userProvider.getUser(target);
|
|
57
51
|
// check requesting user has target user's org admin role
|
|
58
52
|
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
59
53
|
// check requesting user has global admin
|
|
60
54
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
61
55
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
56
|
+
if (!mayImpersonate) {
|
|
57
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
65
58
|
}
|
|
66
|
-
|
|
67
59
|
// allowed to impersonate so "switch" user to target user
|
|
68
60
|
user = targetUser;
|
|
69
61
|
}
|
|
70
|
-
|
|
71
62
|
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
72
|
-
}
|
|
73
|
-
|
|
63
|
+
}
|
|
74
64
|
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
75
65
|
let data = {
|
|
76
|
-
time: Date.now(),
|
|
66
|
+
time: Date.now(),
|
|
77
67
|
user: user
|
|
78
|
-
};
|
|
79
|
-
const token = jwt.sign(data, jwtSecretKey, {expiresIn: process.env.JWT_EXPIRY_TIME});
|
|
68
|
+
};
|
|
69
|
+
const token = jwt.sign(data, jwtSecretKey, { expiresIn: process.env.JWT_EXPIRY_TIME });
|
|
80
70
|
console.log(`Successful login: ${user.id}`);
|
|
81
71
|
return token;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
75
|
+
}
|
|
85
76
|
};
|
|
86
77
|
/**
|
|
87
78
|
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
88
79
|
*/
|
|
89
80
|
const mfaRegister = async (appName, login, userProvider) => {
|
|
90
|
-
return new Promise(async (resolve,
|
|
91
|
-
let user = await userProvider.getUser(login);
|
|
92
|
-
|
|
81
|
+
return new Promise(async (resolve, _reject) => {
|
|
82
|
+
let user = await userProvider.getUser(login);
|
|
93
83
|
const secret = speakeasy.generateSecret({
|
|
94
|
-
name: `${appName} (${login})`,
|
|
84
|
+
name: `${appName} (${login})`,
|
|
95
85
|
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
86
|
+
if (!user.mfa)
|
|
87
|
+
user.mfa = {
|
|
88
|
+
secret: {
|
|
89
|
+
temp: undefined,
|
|
90
|
+
actual: undefined,
|
|
91
|
+
enabled: true
|
|
92
|
+
}
|
|
93
|
+
};
|
|
104
94
|
user.mfa.secret.temp = secret.base32;
|
|
105
95
|
user.mfa.secret.actual = undefined;
|
|
106
|
-
|
|
107
96
|
await userProvider.putUser(user);
|
|
108
|
-
|
|
109
|
-
qrcode.toDataURL(secret.otpauth_url, (err, data)=>{
|
|
97
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data) => {
|
|
110
98
|
if (err) {
|
|
111
|
-
throw new Error('Error generating QR code');
|
|
112
|
-
}
|
|
99
|
+
throw new Error('Error generating QR code');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
113
102
|
// Send the QR code URL and the secret
|
|
114
|
-
resolve({
|
|
115
|
-
qr_code: data,
|
|
116
|
-
secret: secret.base32
|
|
103
|
+
resolve({
|
|
104
|
+
qr_code: data,
|
|
105
|
+
secret: secret.base32
|
|
117
106
|
});
|
|
118
107
|
}
|
|
119
108
|
});
|
|
120
|
-
})
|
|
109
|
+
});
|
|
121
110
|
};
|
|
122
|
-
|
|
123
111
|
/**
|
|
124
112
|
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
125
113
|
*/
|
|
126
114
|
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
115
|
+
var _a, _b, _c, _d;
|
|
127
116
|
const token = mfaToken;
|
|
128
|
-
|
|
129
117
|
// load user
|
|
130
118
|
let user = await userProvider.getUser(login);
|
|
131
|
-
|
|
132
119
|
// Verify the token using the saved secret
|
|
133
120
|
const verified = speakeasy.totp.verify({
|
|
134
|
-
secret: user.mfa
|
|
121
|
+
secret: (_b = (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.secret) === null || _b === void 0 ? void 0 : _b.temp,
|
|
135
122
|
encoding: 'base32',
|
|
136
123
|
token,
|
|
137
124
|
});
|
|
138
|
-
|
|
139
125
|
if (verified) {
|
|
140
|
-
user.mfa.secret.actual = user.mfa
|
|
141
|
-
await userProvider.putUser(user);
|
|
126
|
+
user.mfa.secret.actual = (_d = (_c = user.mfa) === null || _c === void 0 ? void 0 : _c.secret) === null || _d === void 0 ? void 0 : _d.temp;
|
|
127
|
+
await userProvider.putUser(user);
|
|
142
128
|
return true;
|
|
143
|
-
}
|
|
144
|
-
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
145
132
|
return false;
|
|
146
|
-
}
|
|
133
|
+
}
|
|
147
134
|
};
|
|
148
|
-
|
|
149
135
|
const mfaEnabled = async (login, userProvider) => {
|
|
136
|
+
var _a;
|
|
150
137
|
let user = await userProvider.getUser(login);
|
|
151
|
-
return user.mfa
|
|
138
|
+
return (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
|
|
152
139
|
};
|
|
153
140
|
|
|
154
141
|
export { authenticate, mfaEnabled, mfaRegister, mfaVerify };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const speakeasy=require("speakeasy"),qrcode=require("qrcode"),md5=require("md5"),authenticate=async(e,t,a,r,
|
|
1
|
+
const speakeasy=require("speakeasy"),qrcode=require("qrcode"),md5=require("md5"),jwt=require("jsonwebtoken"),authenticate=async(e,t,a,r,o,i)=>{var n,s,c;let l=await o.getUser(e);if(null===(n=l.mfa)||void 0===n?void 0:n.enabled){if(!speakeasy.totp.verify({secret:null===(c=null===(s=l.mfa)||void 0===s?void 0:s.secret)||void 0===c?void 0:c.actual,encoding:"base32",mfaToken:a,window:1}))throw new Error(`Failed authentication attempt ${e}`)}if(md5(t||"")==l.password){const e=r,t=l;if(e){let a=!1;if(e.startsWith("@")){if(a=a||i.canImpersonate(l,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);i.impersonate(l,e)}else{const r=await o.getUser(e);if(a=a||i.canImpersonate(l,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);l=r}console.info(`Impersonate success. From: ${t.login} into ${e}`)}let a=process.env.JWT_SECRET_KEY,n={time:Date.now(),user:l};const s=jwt.sign(n,a,{expiresIn:process.env.JWT_EXPIRY_TIME});return console.log(`Successful login: ${l.id}`),s}throw new Error(`Failed authentication attempt ${e}`)},mfaRegister=async(e,t,a)=>new Promise((async(r,o)=>{let i=await a.getUser(t);const n=speakeasy.generateSecret({name:`${e} (${t})`});i.mfa||(i.mfa={secret:{temp:void 0,actual:void 0,enabled:!0}}),i.mfa.secret.temp=n.base32,i.mfa.secret.actual=void 0,await a.putUser(i),qrcode.toDataURL(n.otpauth_url,((e,t)=>{if(e)throw new Error("Error generating QR code");r({qr_code:t,secret:n.base32})}))})),mfaVerify=async(e,t,a)=>{var r,o,i,n;const s=t;let c=await a.getUser(e);return speakeasy.totp.verify({secret:null===(o=null===(r=c.mfa)||void 0===r?void 0:r.secret)||void 0===o?void 0:o.temp,encoding:"base32",token:s})?(c.mfa.secret.actual=null===(n=null===(i=c.mfa)||void 0===i?void 0:i.secret)||void 0===n?void 0:n.temp,await a.putUser(c),!0):(console.log(`Failed mfa verification for ${e}`),!1)},mfaEnabled=async(e,t)=>{var a;return null===(a=(await t.getUser(e)).mfa)||void 0===a?void 0:a.enabled};export{authenticate,mfaEnabled,mfaRegister,mfaVerify};
|
package/dist/pico-auth.umd.js
CHANGED
|
@@ -7,47 +7,42 @@
|
|
|
7
7
|
const speakeasy = require('speakeasy');
|
|
8
8
|
const qrcode = require('qrcode');
|
|
9
9
|
const md5 = require("md5");
|
|
10
|
-
|
|
10
|
+
const jwt = require('jsonwebtoken');
|
|
11
11
|
/**
|
|
12
12
|
* When mfaToken is provided
|
|
13
13
|
*/
|
|
14
14
|
const authenticate = async (login, password, mfaToken, impersonateEntity, userProvider, impersonateProvider) => {
|
|
15
|
+
var _a, _b, _c;
|
|
15
16
|
let user = await userProvider.getUser(login);
|
|
16
|
-
|
|
17
|
-
if(user.mfa?.enabled){
|
|
17
|
+
if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
18
18
|
// Validate the token against the user's saved secret
|
|
19
19
|
const validated = speakeasy.totp.verify({
|
|
20
|
-
secret: user.mfa
|
|
20
|
+
secret: (_c = (_b = user.mfa) === null || _b === void 0 ? void 0 : _b.secret) === null || _c === void 0 ? void 0 : _c.actual,
|
|
21
21
|
encoding: 'base32',
|
|
22
22
|
mfaToken,
|
|
23
23
|
window: 1, // Adjust window size if tokens have a margin of error
|
|
24
24
|
});
|
|
25
|
-
if(!validated)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if(md5(password||'') == user.password){
|
|
25
|
+
if (!validated)
|
|
26
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
27
|
+
}
|
|
28
|
+
if (md5(password || '') == user.password) {
|
|
29
29
|
// check if impersonate mode - this is not yet implemented fully just copy pasta from GRM project
|
|
30
30
|
const target = impersonateEntity; // either target user login or @organizationId
|
|
31
31
|
const originalUser = user;
|
|
32
|
-
|
|
33
|
-
if(target){
|
|
34
|
-
|
|
32
|
+
if (target) {
|
|
35
33
|
// impersonate flow
|
|
36
34
|
let mayImpersonate = false;
|
|
37
|
-
|
|
38
35
|
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
39
|
-
if(target.startsWith("@")){
|
|
36
|
+
if (target.startsWith("@")) {
|
|
40
37
|
// only organization impersonation
|
|
41
38
|
// check requesting user has global admin
|
|
42
39
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
43
40
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
44
41
|
// mayImpersonate = true;
|
|
45
42
|
// todo check org exists
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
43
|
+
if (!mayImpersonate) {
|
|
44
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
45
|
+
}
|
|
51
46
|
// switch original user organization_id
|
|
52
47
|
impersonateProvider.impersonate(user, target);
|
|
53
48
|
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
@@ -58,103 +53,95 @@
|
|
|
58
53
|
else {
|
|
59
54
|
// full user impersonation
|
|
60
55
|
// load target user
|
|
61
|
-
const targetUser = await userProvider.getUser(target);
|
|
62
|
-
|
|
56
|
+
const targetUser = await userProvider.getUser(target);
|
|
63
57
|
// check requesting user has target user's org admin role
|
|
64
58
|
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
65
59
|
// check requesting user has global admin
|
|
66
60
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
67
61
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
62
|
+
if (!mayImpersonate) {
|
|
63
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
71
64
|
}
|
|
72
|
-
|
|
73
65
|
// allowed to impersonate so "switch" user to target user
|
|
74
66
|
user = targetUser;
|
|
75
67
|
}
|
|
76
|
-
|
|
77
68
|
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
78
|
-
}
|
|
79
|
-
|
|
69
|
+
}
|
|
80
70
|
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
81
71
|
let data = {
|
|
82
|
-
time: Date.now(),
|
|
72
|
+
time: Date.now(),
|
|
83
73
|
user: user
|
|
84
|
-
};
|
|
85
|
-
const token = jwt.sign(data, jwtSecretKey, {expiresIn: process.env.JWT_EXPIRY_TIME});
|
|
74
|
+
};
|
|
75
|
+
const token = jwt.sign(data, jwtSecretKey, { expiresIn: process.env.JWT_EXPIRY_TIME });
|
|
86
76
|
console.log(`Successful login: ${user.id}`);
|
|
87
77
|
return token;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
81
|
+
}
|
|
91
82
|
};
|
|
92
83
|
/**
|
|
93
84
|
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
94
85
|
*/
|
|
95
86
|
const mfaRegister = async (appName, login, userProvider) => {
|
|
96
|
-
return new Promise(async (resolve,
|
|
97
|
-
let user = await userProvider.getUser(login);
|
|
98
|
-
|
|
87
|
+
return new Promise(async (resolve, _reject) => {
|
|
88
|
+
let user = await userProvider.getUser(login);
|
|
99
89
|
const secret = speakeasy.generateSecret({
|
|
100
|
-
name: `${appName} (${login})`,
|
|
90
|
+
name: `${appName} (${login})`,
|
|
101
91
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
92
|
+
if (!user.mfa)
|
|
93
|
+
user.mfa = {
|
|
94
|
+
secret: {
|
|
95
|
+
temp: undefined,
|
|
96
|
+
actual: undefined,
|
|
97
|
+
enabled: true
|
|
98
|
+
}
|
|
99
|
+
};
|
|
110
100
|
user.mfa.secret.temp = secret.base32;
|
|
111
101
|
user.mfa.secret.actual = undefined;
|
|
112
|
-
|
|
113
102
|
await userProvider.putUser(user);
|
|
114
|
-
|
|
115
|
-
qrcode.toDataURL(secret.otpauth_url, (err, data)=>{
|
|
103
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data) => {
|
|
116
104
|
if (err) {
|
|
117
|
-
throw new Error('Error generating QR code');
|
|
118
|
-
}
|
|
105
|
+
throw new Error('Error generating QR code');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
119
108
|
// Send the QR code URL and the secret
|
|
120
|
-
resolve({
|
|
121
|
-
qr_code: data,
|
|
122
|
-
secret: secret.base32
|
|
109
|
+
resolve({
|
|
110
|
+
qr_code: data,
|
|
111
|
+
secret: secret.base32
|
|
123
112
|
});
|
|
124
113
|
}
|
|
125
114
|
});
|
|
126
|
-
})
|
|
115
|
+
});
|
|
127
116
|
};
|
|
128
|
-
|
|
129
117
|
/**
|
|
130
118
|
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
131
119
|
*/
|
|
132
120
|
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
121
|
+
var _a, _b, _c, _d;
|
|
133
122
|
const token = mfaToken;
|
|
134
|
-
|
|
135
123
|
// load user
|
|
136
124
|
let user = await userProvider.getUser(login);
|
|
137
|
-
|
|
138
125
|
// Verify the token using the saved secret
|
|
139
126
|
const verified = speakeasy.totp.verify({
|
|
140
|
-
secret: user.mfa
|
|
127
|
+
secret: (_b = (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.secret) === null || _b === void 0 ? void 0 : _b.temp,
|
|
141
128
|
encoding: 'base32',
|
|
142
129
|
token,
|
|
143
130
|
});
|
|
144
|
-
|
|
145
131
|
if (verified) {
|
|
146
|
-
user.mfa.secret.actual = user.mfa
|
|
147
|
-
await userProvider.putUser(user);
|
|
132
|
+
user.mfa.secret.actual = (_d = (_c = user.mfa) === null || _c === void 0 ? void 0 : _c.secret) === null || _d === void 0 ? void 0 : _d.temp;
|
|
133
|
+
await userProvider.putUser(user);
|
|
148
134
|
return true;
|
|
149
|
-
}
|
|
150
|
-
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
151
138
|
return false;
|
|
152
|
-
}
|
|
139
|
+
}
|
|
153
140
|
};
|
|
154
|
-
|
|
155
141
|
const mfaEnabled = async (login, userProvider) => {
|
|
142
|
+
var _a;
|
|
156
143
|
let user = await userProvider.getUser(login);
|
|
157
|
-
return user.mfa
|
|
144
|
+
return (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
|
|
158
145
|
};
|
|
159
146
|
|
|
160
147
|
exports.authenticate = authenticate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).picoAuth={})}(this,(function(e){"use strict";const t=require("speakeasy"),
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).picoAuth={})}(this,(function(e){"use strict";const t=require("speakeasy"),o=require("qrcode"),a=require("md5"),r=require("jsonwebtoken");e.authenticate=async(e,o,i,n,s,c)=>{var l,d,f;let u=await s.getUser(e);if(null===(l=u.mfa)||void 0===l?void 0:l.enabled){if(!t.totp.verify({secret:null===(f=null===(d=u.mfa)||void 0===d?void 0:d.secret)||void 0===f?void 0:f.actual,encoding:"base32",mfaToken:i,window:1}))throw new Error(`Failed authentication attempt ${e}`)}if(a(o||"")==u.password){const e=n,t=u;if(e){let o=!1;if(e.startsWith("@")){if(o=o||c.canImpersonate(u,e),!o)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);c.impersonate(u,e)}else{const a=await s.getUser(e);if(o=o||c.canImpersonate(u,e),!o)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);u=a}console.info(`Impersonate success. From: ${t.login} into ${e}`)}let o=process.env.JWT_SECRET_KEY,a={time:Date.now(),user:u};const i=r.sign(a,o,{expiresIn:process.env.JWT_EXPIRY_TIME});return console.log(`Successful login: ${u.id}`),i}throw new Error(`Failed authentication attempt ${e}`)},e.mfaEnabled=async(e,t)=>{var o;return null===(o=(await t.getUser(e)).mfa)||void 0===o?void 0:o.enabled},e.mfaRegister=async(e,a,r)=>new Promise((async(i,n)=>{let s=await r.getUser(a);const c=t.generateSecret({name:`${e} (${a})`});s.mfa||(s.mfa={secret:{temp:void 0,actual:void 0,enabled:!0}}),s.mfa.secret.temp=c.base32,s.mfa.secret.actual=void 0,await r.putUser(s),o.toDataURL(c.otpauth_url,((e,t)=>{if(e)throw new Error("Error generating QR code");i({qr_code:t,secret:c.base32})}))})),e.mfaVerify=async(e,o,a)=>{var r,i,n,s;const c=o;let l=await a.getUser(e);return t.totp.verify({secret:null===(i=null===(r=l.mfa)||void 0===r?void 0:r.secret)||void 0===i?void 0:i.temp,encoding:"base32",token:c})?(l.mfa.secret.actual=null===(s=null===(n=l.mfa)||void 0===n?void 0:n.secret)||void 0===s?void 0:s.temp,await a.putUser(l),!0):(console.log(`Failed mfa verification for ${e}`),!1)},Object.defineProperty(e,"__esModule",{value:!0})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pico-auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Minimal auth with user/pass, impersonation and mfa authentication",
|
|
5
5
|
"main": "dist/pico-auth.umd.js",
|
|
6
6
|
"types": "dist/pico-auth.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"build:types": "tsc -t esnext --moduleResolution node -d --emitDeclarationOnly --outFile dist/pico-auth.d.ts src/pico-auth.ts",
|
|
38
38
|
"test": "env TS_NODE_PROJECT=\"tsconfig-test.json\" mocha -r ts-node/register --require source-map-support/register --recursive **/test/**/*.test.ts",
|
|
39
39
|
"coverage": "nyc --reporter html --reporter text npm test",
|
|
40
|
-
"release-minor": "npm install && npm update && npm run build && npm run coverage && npm version minor && git push origin && git push origin --tags"
|
|
40
|
+
"release-minor": "npm install && npm update && npm run build && npm run coverage && npm version minor && git push origin && git push origin --tags && npm publish"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"dist"
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"md5": "^2.3.0",
|
|
49
49
|
"speakeasy": "2.0.0",
|
|
50
|
-
"qrcode": "1.5.4"
|
|
50
|
+
"qrcode": "1.5.4",
|
|
51
|
+
"jsonwebtoken": "^8.5.1"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@rollup/plugin-typescript": "^6.1.0",
|