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.
@@ -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 "core/auth";
2
+ export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "./auth";
18
3
  }
@@ -1,42 +1,47 @@
1
1
  const speakeasy = require('speakeasy');
2
2
  const qrcode = require('qrcode');
3
3
  const md5 = require("md5");
4
- const jwt = require('jsonwebtoken');
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
- if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
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: (_c = (_b = user.mfa) === null || _b === void 0 ? void 0 : _b.secret) === null || _c === void 0 ? void 0 : _c.actual,
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 (!validated)
20
- throw new Error(`Failed authentication attempt ${login}`);
21
- }
22
- if (md5(password || '') == user.password) {
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
- if (target) {
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 (target.startsWith("@")) {
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
- if (!mayImpersonate) {
38
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
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
- if (!mayImpersonate) {
57
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
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, { expiresIn: process.env.JWT_EXPIRY_TIME });
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
- else {
74
- throw new Error(`Failed authentication attempt ${login}`);
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, _reject) => {
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
- if (!user.mfa)
87
- user.mfa = {
88
- secret: {
89
- temp: undefined,
90
- actual: undefined,
91
- enabled: true
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
- qrcode.toDataURL(secret.otpauth_url, (err, data) => {
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: (_b = (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.secret) === null || _b === void 0 ? void 0 : _b.temp,
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 = (_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);
140
+ user.mfa.secret.actual = user.mfa?.secret?.temp;
141
+ await userProvider.putUser(user);
128
142
  return true;
129
- }
130
- else {
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 (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
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"),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};
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};
@@ -7,42 +7,47 @@
7
7
  const speakeasy = require('speakeasy');
8
8
  const qrcode = require('qrcode');
9
9
  const md5 = require("md5");
10
- const jwt = require('jsonwebtoken');
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
- if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
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: (_c = (_b = user.mfa) === null || _b === void 0 ? void 0 : _b.secret) === null || _c === void 0 ? void 0 : _c.actual,
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 (!validated)
26
- throw new Error(`Failed authentication attempt ${login}`);
27
- }
28
- if (md5(password || '') == user.password) {
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
- if (target) {
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 (target.startsWith("@")) {
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
- if (!mayImpersonate) {
44
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
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
- if (!mayImpersonate) {
63
- throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
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, { expiresIn: process.env.JWT_EXPIRY_TIME });
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
- else {
80
- throw new Error(`Failed authentication attempt ${login}`);
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, _reject) => {
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
- if (!user.mfa)
93
- user.mfa = {
94
- secret: {
95
- temp: undefined,
96
- actual: undefined,
97
- enabled: true
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
- qrcode.toDataURL(secret.otpauth_url, (err, data) => {
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: (_b = (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.secret) === null || _b === void 0 ? void 0 : _b.temp,
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 = (_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);
146
+ user.mfa.secret.actual = user.mfa?.secret?.temp;
147
+ await userProvider.putUser(user);
134
148
  return true;
135
- }
136
- else {
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 (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
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"),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})}));
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.2",
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 && npm publish"
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",