pico-auth 0.0.3 → 0.0.5

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.
@@ -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 "./auth";
17
+ export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "core/auth";
3
18
  }
@@ -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?.secret?.actual,
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) throw new Error(`Failed authentication attempt ${login}`)
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
- if(!mayImpersonate){
42
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`)
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
- if(!mayImpersonate){
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
- }else {
83
- throw new Error(`Failed authentication attempt ${login}`)
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, reject)=>{
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
- if(!user.mfa) user.mfa = {
98
- secret: {
99
- temp: undefined,
100
- actual: undefined,
101
- enabled: true
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
- } else {
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?.secret?.temp,
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?.secret?.temp;
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
- }else {
144
- console.log(`Failed mfa verification for ${login}`);
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?.enabled;
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,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};
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};
@@ -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?.secret?.actual,
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) throw new Error(`Failed authentication attempt ${login}`)
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
- if(!mayImpersonate){
48
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`)
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
- if(!mayImpersonate){
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
- }else {
89
- throw new Error(`Failed authentication attempt ${login}`)
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, reject)=>{
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
- if(!user.mfa) user.mfa = {
104
- secret: {
105
- temp: undefined,
106
- actual: undefined,
107
- enabled: true
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
- } else {
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?.secret?.temp,
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?.secret?.temp;
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
- }else {
150
- console.log(`Failed mfa verification for ${login}`);
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?.enabled;
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"),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})}));
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",
3
+ "version": "0.0.5",
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",