pico-auth 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pico-auth.d.ts +1 -16
- package/dist/pico-auth.esm.js +66 -53
- package/dist/pico-auth.esm.min.js +1 -1
- package/dist/pico-auth.umd.js +66 -53
- package/dist/pico-auth.umd.min.js +1 -1
- package/package.json +3 -4
package/dist/pico-auth.d.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
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
|
-
}
|
|
16
1
|
declare module "pico-auth" {
|
|
17
|
-
export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "
|
|
2
|
+
export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "./auth";
|
|
18
3
|
}
|
package/dist/pico-auth.esm.js
CHANGED
|
@@ -1,42 +1,47 @@
|
|
|
1
1
|
const speakeasy = require('speakeasy');
|
|
2
2
|
const qrcode = require('qrcode');
|
|
3
3
|
const md5 = require("md5");
|
|
4
|
-
|
|
4
|
+
|
|
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;
|
|
10
9
|
let user = await userProvider.getUser(login);
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
if(user.mfa?.enabled){
|
|
12
12
|
// Validate the token against the user's saved secret
|
|
13
13
|
const validated = speakeasy.totp.verify({
|
|
14
|
-
secret:
|
|
14
|
+
secret: user.mfa?.secret?.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
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if
|
|
19
|
+
if(!validated) throw new Error(`Failed authentication attempt ${login}`)
|
|
20
|
+
}
|
|
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
|
-
|
|
26
|
+
|
|
27
|
+
if(target){
|
|
28
|
+
|
|
27
29
|
// impersonate flow
|
|
28
30
|
let mayImpersonate = false;
|
|
31
|
+
|
|
29
32
|
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
30
|
-
if
|
|
33
|
+
if(target.startsWith("@")){
|
|
31
34
|
// only organization impersonation
|
|
32
35
|
// check requesting user has global admin
|
|
33
36
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
34
37
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
35
38
|
// mayImpersonate = true;
|
|
36
39
|
// todo check org exists
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
|
|
41
|
+
if(!mayImpersonate){
|
|
42
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`)
|
|
43
|
+
}
|
|
44
|
+
|
|
40
45
|
// switch original user organization_id
|
|
41
46
|
impersonateProvider.impersonate(user, target);
|
|
42
47
|
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
@@ -47,95 +52,103 @@ const authenticate = async (login, password, mfaToken, impersonateEntity, userPr
|
|
|
47
52
|
else {
|
|
48
53
|
// full user impersonation
|
|
49
54
|
// load target user
|
|
50
|
-
const targetUser = await userProvider.getUser(target);
|
|
55
|
+
const targetUser = await userProvider.getUser(target);
|
|
56
|
+
|
|
51
57
|
// check requesting user has target user's org admin role
|
|
52
58
|
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
53
59
|
// check requesting user has global admin
|
|
54
60
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
55
61
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
|
|
63
|
+
if(!mayImpersonate){
|
|
64
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
58
65
|
}
|
|
66
|
+
|
|
59
67
|
// allowed to impersonate so "switch" user to target user
|
|
60
68
|
user = targetUser;
|
|
61
69
|
}
|
|
70
|
+
|
|
62
71
|
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
63
|
-
}
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
65
75
|
let data = {
|
|
66
|
-
time: Date.now(),
|
|
76
|
+
time: Date.now(),
|
|
67
77
|
user: user
|
|
68
|
-
};
|
|
69
|
-
const token = jwt.sign(data, jwtSecretKey, {
|
|
78
|
+
};
|
|
79
|
+
const token = jwt.sign(data, jwtSecretKey, {expiresIn: process.env.JWT_EXPIRY_TIME});
|
|
70
80
|
console.log(`Successful login: ${user.id}`);
|
|
71
81
|
return token;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
82
|
+
}else {
|
|
83
|
+
throw new Error(`Failed authentication attempt ${login}`)
|
|
84
|
+
}
|
|
76
85
|
};
|
|
77
86
|
/**
|
|
78
87
|
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
79
88
|
*/
|
|
80
89
|
const mfaRegister = async (appName, login, userProvider) => {
|
|
81
|
-
return new Promise(async (resolve,
|
|
82
|
-
let user = await userProvider.getUser(login);
|
|
90
|
+
return new Promise(async (resolve, reject)=>{
|
|
91
|
+
let user = await userProvider.getUser(login);
|
|
92
|
+
|
|
83
93
|
const secret = speakeasy.generateSecret({
|
|
84
|
-
name: `${appName} (${login})`,
|
|
94
|
+
name: `${appName} (${login})`,
|
|
85
95
|
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
|
|
97
|
+
if(!user.mfa) user.mfa = {
|
|
98
|
+
secret: {
|
|
99
|
+
temp: undefined,
|
|
100
|
+
actual: undefined,
|
|
101
|
+
enabled: true
|
|
102
|
+
}
|
|
103
|
+
};
|
|
94
104
|
user.mfa.secret.temp = secret.base32;
|
|
95
105
|
user.mfa.secret.actual = undefined;
|
|
106
|
+
|
|
96
107
|
await userProvider.putUser(user);
|
|
97
|
-
|
|
108
|
+
|
|
109
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data)=>{
|
|
98
110
|
if (err) {
|
|
99
|
-
throw new Error('Error generating QR code');
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
111
|
+
throw new Error('Error generating QR code');
|
|
112
|
+
} else {
|
|
102
113
|
// Send the QR code URL and the secret
|
|
103
|
-
resolve({
|
|
104
|
-
qr_code: data,
|
|
105
|
-
secret: secret.base32
|
|
114
|
+
resolve({
|
|
115
|
+
qr_code: data,
|
|
116
|
+
secret: secret.base32
|
|
106
117
|
});
|
|
107
118
|
}
|
|
108
119
|
});
|
|
109
|
-
})
|
|
120
|
+
})
|
|
110
121
|
};
|
|
122
|
+
|
|
111
123
|
/**
|
|
112
124
|
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
113
125
|
*/
|
|
114
126
|
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
115
|
-
var _a, _b, _c, _d;
|
|
116
127
|
const token = mfaToken;
|
|
128
|
+
|
|
117
129
|
// load user
|
|
118
130
|
let user = await userProvider.getUser(login);
|
|
131
|
+
|
|
119
132
|
// Verify the token using the saved secret
|
|
120
133
|
const verified = speakeasy.totp.verify({
|
|
121
|
-
secret:
|
|
134
|
+
secret: user.mfa?.secret?.temp,
|
|
122
135
|
encoding: 'base32',
|
|
123
136
|
token,
|
|
124
137
|
});
|
|
138
|
+
|
|
125
139
|
if (verified) {
|
|
126
|
-
user.mfa.secret.actual =
|
|
127
|
-
await userProvider.putUser(user);
|
|
140
|
+
user.mfa.secret.actual = user.mfa?.secret?.temp;
|
|
141
|
+
await userProvider.putUser(user);
|
|
128
142
|
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
console.log(`Failed mfa verification for ${login}`);
|
|
143
|
+
}else {
|
|
144
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
132
145
|
return false;
|
|
133
|
-
}
|
|
146
|
+
}
|
|
134
147
|
};
|
|
148
|
+
|
|
135
149
|
const mfaEnabled = async (login, userProvider) => {
|
|
136
|
-
var _a;
|
|
137
150
|
let user = await userProvider.getUser(login);
|
|
138
|
-
return
|
|
151
|
+
return user.mfa?.enabled;
|
|
139
152
|
};
|
|
140
153
|
|
|
141
154
|
export { authenticate, mfaEnabled, mfaRegister, mfaVerify };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const speakeasy=require("speakeasy"),qrcode=require("qrcode"),md5=require("md5"),
|
|
1
|
+
const speakeasy=require("speakeasy"),qrcode=require("qrcode"),md5=require("md5"),authenticate=async(e,t,a,r,s,o)=>{let n=await s.getUser(e);if(n.mfa?.enabled){if(!speakeasy.totp.verify({secret:n.mfa?.secret?.actual,encoding:"base32",mfaToken:a,window:1}))throw new Error(`Failed authentication attempt ${e}`)}if(md5(t||"")==n.password){const e=r,t=n;if(e){let a=!1;if(e.startsWith("@")){if(a=a||o.canImpersonate(n,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);o.impersonate(n,e)}else{const r=await s.getUser(e);if(a=a||o.canImpersonate(n,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);n=r}console.info(`Impersonate success. From: ${t.login} into ${e}`)}let a=process.env.JWT_SECRET_KEY,i={time:Date.now(),user:n};const c=jwt.sign(i,a,{expiresIn:process.env.JWT_EXPIRY_TIME});return console.log(`Successful login: ${n.id}`),c}throw new Error(`Failed authentication attempt ${e}`)},mfaRegister=async(e,t,a)=>new Promise((async(r,s)=>{let o=await a.getUser(t);const n=speakeasy.generateSecret({name:`${e} (${t})`});o.mfa||(o.mfa={secret:{temp:void 0,actual:void 0,enabled:!0}}),o.mfa.secret.temp=n.base32,o.mfa.secret.actual=void 0,await a.putUser(o),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)=>{const r=t;let s=await a.getUser(e);return speakeasy.totp.verify({secret:s.mfa?.secret?.temp,encoding:"base32",token:r})?(s.mfa.secret.actual=s.mfa?.secret?.temp,await a.putUser(s),!0):(console.log(`Failed mfa verification for ${e}`),!1)},mfaEnabled=async(e,t)=>{let a=await t.getUser(e);return a.mfa?.enabled};export{authenticate,mfaEnabled,mfaRegister,mfaVerify};
|
package/dist/pico-auth.umd.js
CHANGED
|
@@ -7,42 +7,47 @@
|
|
|
7
7
|
const speakeasy = require('speakeasy');
|
|
8
8
|
const qrcode = require('qrcode');
|
|
9
9
|
const md5 = require("md5");
|
|
10
|
-
|
|
10
|
+
|
|
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;
|
|
16
15
|
let user = await userProvider.getUser(login);
|
|
17
|
-
|
|
16
|
+
|
|
17
|
+
if(user.mfa?.enabled){
|
|
18
18
|
// Validate the token against the user's saved secret
|
|
19
19
|
const validated = speakeasy.totp.verify({
|
|
20
|
-
secret:
|
|
20
|
+
secret: user.mfa?.secret?.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
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if
|
|
25
|
+
if(!validated) throw new Error(`Failed authentication attempt ${login}`)
|
|
26
|
+
}
|
|
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
|
-
|
|
32
|
+
|
|
33
|
+
if(target){
|
|
34
|
+
|
|
33
35
|
// impersonate flow
|
|
34
36
|
let mayImpersonate = false;
|
|
37
|
+
|
|
35
38
|
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
36
|
-
if
|
|
39
|
+
if(target.startsWith("@")){
|
|
37
40
|
// only organization impersonation
|
|
38
41
|
// check requesting user has global admin
|
|
39
42
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
40
43
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
41
44
|
// mayImpersonate = true;
|
|
42
45
|
// todo check org exists
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
|
|
47
|
+
if(!mayImpersonate){
|
|
48
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
// switch original user organization_id
|
|
47
52
|
impersonateProvider.impersonate(user, target);
|
|
48
53
|
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
@@ -53,95 +58,103 @@
|
|
|
53
58
|
else {
|
|
54
59
|
// full user impersonation
|
|
55
60
|
// load target user
|
|
56
|
-
const targetUser = await userProvider.getUser(target);
|
|
61
|
+
const targetUser = await userProvider.getUser(target);
|
|
62
|
+
|
|
57
63
|
// check requesting user has target user's org admin role
|
|
58
64
|
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
59
65
|
// check requesting user has global admin
|
|
60
66
|
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
61
67
|
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
|
|
69
|
+
if(!mayImpersonate){
|
|
70
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
64
71
|
}
|
|
72
|
+
|
|
65
73
|
// allowed to impersonate so "switch" user to target user
|
|
66
74
|
user = targetUser;
|
|
67
75
|
}
|
|
76
|
+
|
|
68
77
|
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
69
|
-
}
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
71
81
|
let data = {
|
|
72
|
-
time: Date.now(),
|
|
82
|
+
time: Date.now(),
|
|
73
83
|
user: user
|
|
74
|
-
};
|
|
75
|
-
const token = jwt.sign(data, jwtSecretKey, {
|
|
84
|
+
};
|
|
85
|
+
const token = jwt.sign(data, jwtSecretKey, {expiresIn: process.env.JWT_EXPIRY_TIME});
|
|
76
86
|
console.log(`Successful login: ${user.id}`);
|
|
77
87
|
return token;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
88
|
+
}else {
|
|
89
|
+
throw new Error(`Failed authentication attempt ${login}`)
|
|
90
|
+
}
|
|
82
91
|
};
|
|
83
92
|
/**
|
|
84
93
|
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
85
94
|
*/
|
|
86
95
|
const mfaRegister = async (appName, login, userProvider) => {
|
|
87
|
-
return new Promise(async (resolve,
|
|
88
|
-
let user = await userProvider.getUser(login);
|
|
96
|
+
return new Promise(async (resolve, reject)=>{
|
|
97
|
+
let user = await userProvider.getUser(login);
|
|
98
|
+
|
|
89
99
|
const secret = speakeasy.generateSecret({
|
|
90
|
-
name: `${appName} (${login})`,
|
|
100
|
+
name: `${appName} (${login})`,
|
|
91
101
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
|
|
103
|
+
if(!user.mfa) user.mfa = {
|
|
104
|
+
secret: {
|
|
105
|
+
temp: undefined,
|
|
106
|
+
actual: undefined,
|
|
107
|
+
enabled: true
|
|
108
|
+
}
|
|
109
|
+
};
|
|
100
110
|
user.mfa.secret.temp = secret.base32;
|
|
101
111
|
user.mfa.secret.actual = undefined;
|
|
112
|
+
|
|
102
113
|
await userProvider.putUser(user);
|
|
103
|
-
|
|
114
|
+
|
|
115
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data)=>{
|
|
104
116
|
if (err) {
|
|
105
|
-
throw new Error('Error generating QR code');
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
117
|
+
throw new Error('Error generating QR code');
|
|
118
|
+
} else {
|
|
108
119
|
// Send the QR code URL and the secret
|
|
109
|
-
resolve({
|
|
110
|
-
qr_code: data,
|
|
111
|
-
secret: secret.base32
|
|
120
|
+
resolve({
|
|
121
|
+
qr_code: data,
|
|
122
|
+
secret: secret.base32
|
|
112
123
|
});
|
|
113
124
|
}
|
|
114
125
|
});
|
|
115
|
-
})
|
|
126
|
+
})
|
|
116
127
|
};
|
|
128
|
+
|
|
117
129
|
/**
|
|
118
130
|
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
119
131
|
*/
|
|
120
132
|
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
121
|
-
var _a, _b, _c, _d;
|
|
122
133
|
const token = mfaToken;
|
|
134
|
+
|
|
123
135
|
// load user
|
|
124
136
|
let user = await userProvider.getUser(login);
|
|
137
|
+
|
|
125
138
|
// Verify the token using the saved secret
|
|
126
139
|
const verified = speakeasy.totp.verify({
|
|
127
|
-
secret:
|
|
140
|
+
secret: user.mfa?.secret?.temp,
|
|
128
141
|
encoding: 'base32',
|
|
129
142
|
token,
|
|
130
143
|
});
|
|
144
|
+
|
|
131
145
|
if (verified) {
|
|
132
|
-
user.mfa.secret.actual =
|
|
133
|
-
await userProvider.putUser(user);
|
|
146
|
+
user.mfa.secret.actual = user.mfa?.secret?.temp;
|
|
147
|
+
await userProvider.putUser(user);
|
|
134
148
|
return true;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
console.log(`Failed mfa verification for ${login}`);
|
|
149
|
+
}else {
|
|
150
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
138
151
|
return false;
|
|
139
|
-
}
|
|
152
|
+
}
|
|
140
153
|
};
|
|
154
|
+
|
|
141
155
|
const mfaEnabled = async (login, userProvider) => {
|
|
142
|
-
var _a;
|
|
143
156
|
let user = await userProvider.getUser(login);
|
|
144
|
-
return
|
|
157
|
+
return user.mfa?.enabled;
|
|
145
158
|
};
|
|
146
159
|
|
|
147
160
|
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"),a=require("qrcode"),r=require("md5");e.authenticate=async(e,a,o,n,i,s)=>{let c=await i.getUser(e);if(c.mfa?.enabled){if(!t.totp.verify({secret:c.mfa?.secret?.actual,encoding:"base32",mfaToken:o,window:1}))throw new Error(`Failed authentication attempt ${e}`)}if(r(a||"")==c.password){const e=n,t=c;if(e){let a=!1;if(e.startsWith("@")){if(a=a||s.canImpersonate(c,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);s.impersonate(c,e)}else{const r=await i.getUser(e);if(a=a||s.canImpersonate(c,e),!a)throw new Error(`Failed impersonate attempt. From: ${t.id} into ${e}`);c=r}console.info(`Impersonate success. From: ${t.login} into ${e}`)}let a=process.env.JWT_SECRET_KEY,r={time:Date.now(),user:c};const o=jwt.sign(r,a,{expiresIn:process.env.JWT_EXPIRY_TIME});return console.log(`Successful login: ${c.id}`),o}throw new Error(`Failed authentication attempt ${e}`)},e.mfaEnabled=async(e,t)=>{let a=await t.getUser(e);return a.mfa?.enabled},e.mfaRegister=async(e,r,o)=>new Promise((async(n,i)=>{let s=await o.getUser(r);const c=t.generateSecret({name:`${e} (${r})`});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 o.putUser(s),a.toDataURL(c.otpauth_url,((e,t)=>{if(e)throw new Error("Error generating QR code");n({qr_code:t,secret:c.base32})}))})),e.mfaVerify=async(e,a,r)=>{const o=a;let n=await r.getUser(e);return t.totp.verify({secret:n.mfa?.secret?.temp,encoding:"base32",token:o})?(n.mfa.secret.actual=n.mfa?.secret?.temp,await r.putUser(n),!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.3",
|
|
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"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"dist"
|
|
@@ -47,8 +47,7 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"md5": "^2.3.0",
|
|
49
49
|
"speakeasy": "2.0.0",
|
|
50
|
-
"qrcode": "1.5.4"
|
|
51
|
-
"jsonwebtoken": "^8.5.1"
|
|
50
|
+
"qrcode": "1.5.4"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
53
|
"@rollup/plugin-typescript": "^6.1.0",
|