pico-auth 0.0.2
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 +18 -0
- package/dist/pico-auth.esm.js +141 -0
- package/dist/pico-auth.esm.min.js +1 -0
- package/dist/pico-auth.umd.js +154 -0
- package/dist/pico-auth.umd.min.js +1 -0
- package/package.json +101 -0
- package/readme.MD +3 -0
|
@@ -0,0 +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
|
+
}
|
|
16
|
+
declare module "pico-auth" {
|
|
17
|
+
export { mfaRegister, mfaVerify, mfaEnabled, authenticate } from "core/auth";
|
|
18
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const speakeasy = require('speakeasy');
|
|
2
|
+
const qrcode = require('qrcode');
|
|
3
|
+
const md5 = require("md5");
|
|
4
|
+
const jwt = require('jsonwebtoken');
|
|
5
|
+
/**
|
|
6
|
+
* When mfaToken is provided
|
|
7
|
+
*/
|
|
8
|
+
const authenticate = async (login, password, mfaToken, impersonateEntity, userProvider, impersonateProvider) => {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
let user = await userProvider.getUser(login);
|
|
11
|
+
if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
12
|
+
// Validate the token against the user's saved secret
|
|
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,
|
|
15
|
+
encoding: 'base32',
|
|
16
|
+
mfaToken,
|
|
17
|
+
window: 1, // Adjust window size if tokens have a margin of error
|
|
18
|
+
});
|
|
19
|
+
if (!validated)
|
|
20
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
21
|
+
}
|
|
22
|
+
if (md5(password || '') == user.password) {
|
|
23
|
+
// check if impersonate mode - this is not yet implemented fully just copy pasta from GRM project
|
|
24
|
+
const target = impersonateEntity; // either target user login or @organizationId
|
|
25
|
+
const originalUser = user;
|
|
26
|
+
if (target) {
|
|
27
|
+
// impersonate flow
|
|
28
|
+
let mayImpersonate = false;
|
|
29
|
+
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
30
|
+
if (target.startsWith("@")) {
|
|
31
|
+
// only organization impersonation
|
|
32
|
+
// check requesting user has global admin
|
|
33
|
+
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
34
|
+
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
35
|
+
// mayImpersonate = true;
|
|
36
|
+
// todo check org exists
|
|
37
|
+
if (!mayImpersonate) {
|
|
38
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
39
|
+
}
|
|
40
|
+
// switch original user organization_id
|
|
41
|
+
impersonateProvider.impersonate(user, target);
|
|
42
|
+
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
43
|
+
// const organization = await commons.dbApi.adminApi.organization();
|
|
44
|
+
// user.organization_id = parseInt(target.substring(1).trim()); // skip "@" at the beginning
|
|
45
|
+
// user.organization = organization;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// full user impersonation
|
|
49
|
+
// load target user
|
|
50
|
+
const targetUser = await userProvider.getUser(target);
|
|
51
|
+
// check requesting user has target user's org admin role
|
|
52
|
+
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
53
|
+
// check requesting user has global admin
|
|
54
|
+
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
55
|
+
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
56
|
+
if (!mayImpersonate) {
|
|
57
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
58
|
+
}
|
|
59
|
+
// allowed to impersonate so "switch" user to target user
|
|
60
|
+
user = targetUser;
|
|
61
|
+
}
|
|
62
|
+
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
63
|
+
}
|
|
64
|
+
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
65
|
+
let data = {
|
|
66
|
+
time: Date.now(),
|
|
67
|
+
user: user
|
|
68
|
+
};
|
|
69
|
+
const token = jwt.sign(data, jwtSecretKey, { expiresIn: process.env.JWT_EXPIRY_TIME });
|
|
70
|
+
console.log(`Successful login: ${user.id}`);
|
|
71
|
+
return token;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
79
|
+
*/
|
|
80
|
+
const mfaRegister = async (appName, login, userProvider) => {
|
|
81
|
+
return new Promise(async (resolve, _reject) => {
|
|
82
|
+
let user = await userProvider.getUser(login);
|
|
83
|
+
const secret = speakeasy.generateSecret({
|
|
84
|
+
name: `${appName} (${login})`,
|
|
85
|
+
});
|
|
86
|
+
if (!user.mfa)
|
|
87
|
+
user.mfa = {
|
|
88
|
+
secret: {
|
|
89
|
+
temp: undefined,
|
|
90
|
+
actual: undefined,
|
|
91
|
+
enabled: true
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
user.mfa.secret.temp = secret.base32;
|
|
95
|
+
user.mfa.secret.actual = undefined;
|
|
96
|
+
await userProvider.putUser(user);
|
|
97
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data) => {
|
|
98
|
+
if (err) {
|
|
99
|
+
throw new Error('Error generating QR code');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Send the QR code URL and the secret
|
|
103
|
+
resolve({
|
|
104
|
+
qr_code: data,
|
|
105
|
+
secret: secret.base32
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
113
|
+
*/
|
|
114
|
+
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
115
|
+
var _a, _b, _c, _d;
|
|
116
|
+
const token = mfaToken;
|
|
117
|
+
// load user
|
|
118
|
+
let user = await userProvider.getUser(login);
|
|
119
|
+
// Verify the token using the saved secret
|
|
120
|
+
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,
|
|
122
|
+
encoding: 'base32',
|
|
123
|
+
token,
|
|
124
|
+
});
|
|
125
|
+
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);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const mfaEnabled = async (login, userProvider) => {
|
|
136
|
+
var _a;
|
|
137
|
+
let user = await userProvider.getUser(login);
|
|
138
|
+
return (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export { authenticate, mfaEnabled, mfaRegister, mfaVerify };
|
|
@@ -0,0 +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};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.picoAuth = {}));
|
|
5
|
+
})(this, (function (exports) { 'use strict';
|
|
6
|
+
|
|
7
|
+
const speakeasy = require('speakeasy');
|
|
8
|
+
const qrcode = require('qrcode');
|
|
9
|
+
const md5 = require("md5");
|
|
10
|
+
const jwt = require('jsonwebtoken');
|
|
11
|
+
/**
|
|
12
|
+
* When mfaToken is provided
|
|
13
|
+
*/
|
|
14
|
+
const authenticate = async (login, password, mfaToken, impersonateEntity, userProvider, impersonateProvider) => {
|
|
15
|
+
var _a, _b, _c;
|
|
16
|
+
let user = await userProvider.getUser(login);
|
|
17
|
+
if ((_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
18
|
+
// Validate the token against the user's saved secret
|
|
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,
|
|
21
|
+
encoding: 'base32',
|
|
22
|
+
mfaToken,
|
|
23
|
+
window: 1, // Adjust window size if tokens have a margin of error
|
|
24
|
+
});
|
|
25
|
+
if (!validated)
|
|
26
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
27
|
+
}
|
|
28
|
+
if (md5(password || '') == user.password) {
|
|
29
|
+
// check if impersonate mode - this is not yet implemented fully just copy pasta from GRM project
|
|
30
|
+
const target = impersonateEntity; // either target user login or @organizationId
|
|
31
|
+
const originalUser = user;
|
|
32
|
+
if (target) {
|
|
33
|
+
// impersonate flow
|
|
34
|
+
let mayImpersonate = false;
|
|
35
|
+
// check mode - when starts with @ we try to impersonate only to organization, otherwise we impersonate to another user
|
|
36
|
+
if (target.startsWith("@")) {
|
|
37
|
+
// only organization impersonation
|
|
38
|
+
// check requesting user has global admin
|
|
39
|
+
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
40
|
+
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
41
|
+
// mayImpersonate = true;
|
|
42
|
+
// todo check org exists
|
|
43
|
+
if (!mayImpersonate) {
|
|
44
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
45
|
+
}
|
|
46
|
+
// switch original user organization_id
|
|
47
|
+
impersonateProvider.impersonate(user, target);
|
|
48
|
+
// await userManager.impersonateOrganization(user, target.substring(1).trim());
|
|
49
|
+
// const organization = await commons.dbApi.adminApi.organization();
|
|
50
|
+
// user.organization_id = parseInt(target.substring(1).trim()); // skip "@" at the beginning
|
|
51
|
+
// user.organization = organization;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// full user impersonation
|
|
55
|
+
// load target user
|
|
56
|
+
const targetUser = await userProvider.getUser(target);
|
|
57
|
+
// check requesting user has target user's org admin role
|
|
58
|
+
// mayImpersonate = mayImpersonate || (user.organization_id == targetUser.organization_id && user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.ORG_ADMIN))
|
|
59
|
+
// check requesting user has global admin
|
|
60
|
+
// mayImpersonate = mayImpersonate || user.roles.map(role=>role.toUpperCase()).includes(UserManager.CONST.ROLES.GRM_ADMIN);
|
|
61
|
+
mayImpersonate = mayImpersonate || impersonateProvider.canImpersonate(user, target);
|
|
62
|
+
if (!mayImpersonate) {
|
|
63
|
+
throw new Error(`Failed impersonate attempt. From: ${originalUser.id} into ${target}`);
|
|
64
|
+
}
|
|
65
|
+
// allowed to impersonate so "switch" user to target user
|
|
66
|
+
user = targetUser;
|
|
67
|
+
}
|
|
68
|
+
console.info(`Impersonate success. From: ${originalUser.login} into ${target}`);
|
|
69
|
+
}
|
|
70
|
+
let jwtSecretKey = process.env.JWT_SECRET_KEY;
|
|
71
|
+
let data = {
|
|
72
|
+
time: Date.now(),
|
|
73
|
+
user: user
|
|
74
|
+
};
|
|
75
|
+
const token = jwt.sign(data, jwtSecretKey, { expiresIn: process.env.JWT_EXPIRY_TIME });
|
|
76
|
+
console.log(`Successful login: ${user.id}`);
|
|
77
|
+
return token;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new Error(`Failed authentication attempt ${login}`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Will prepare user for MFA activation. Next step is to call verify with token generated in MFA app by the user.
|
|
85
|
+
*/
|
|
86
|
+
const mfaRegister = async (appName, login, userProvider) => {
|
|
87
|
+
return new Promise(async (resolve, _reject) => {
|
|
88
|
+
let user = await userProvider.getUser(login);
|
|
89
|
+
const secret = speakeasy.generateSecret({
|
|
90
|
+
name: `${appName} (${login})`,
|
|
91
|
+
});
|
|
92
|
+
if (!user.mfa)
|
|
93
|
+
user.mfa = {
|
|
94
|
+
secret: {
|
|
95
|
+
temp: undefined,
|
|
96
|
+
actual: undefined,
|
|
97
|
+
enabled: true
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
user.mfa.secret.temp = secret.base32;
|
|
101
|
+
user.mfa.secret.actual = undefined;
|
|
102
|
+
await userProvider.putUser(user);
|
|
103
|
+
qrcode.toDataURL(secret.otpauth_url, (err, data) => {
|
|
104
|
+
if (err) {
|
|
105
|
+
throw new Error('Error generating QR code');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Send the QR code URL and the secret
|
|
109
|
+
resolve({
|
|
110
|
+
qr_code: data,
|
|
111
|
+
secret: secret.base32
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Will return true and fully initialize MFA for user when token verification was ok. Otherwise will result false;
|
|
119
|
+
*/
|
|
120
|
+
const mfaVerify = async (login, mfaToken, userProvider) => {
|
|
121
|
+
var _a, _b, _c, _d;
|
|
122
|
+
const token = mfaToken;
|
|
123
|
+
// load user
|
|
124
|
+
let user = await userProvider.getUser(login);
|
|
125
|
+
// Verify the token using the saved secret
|
|
126
|
+
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,
|
|
128
|
+
encoding: 'base32',
|
|
129
|
+
token,
|
|
130
|
+
});
|
|
131
|
+
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);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log(`Failed mfa verification for ${login}`);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const mfaEnabled = async (login, userProvider) => {
|
|
142
|
+
var _a;
|
|
143
|
+
let user = await userProvider.getUser(login);
|
|
144
|
+
return (_a = user.mfa) === null || _a === void 0 ? void 0 : _a.enabled;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
exports.authenticate = authenticate;
|
|
148
|
+
exports.mfaEnabled = mfaEnabled;
|
|
149
|
+
exports.mfaRegister = mfaRegister;
|
|
150
|
+
exports.mfaVerify = mfaVerify;
|
|
151
|
+
|
|
152
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
153
|
+
|
|
154
|
+
}));
|
|
@@ -0,0 +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})}));
|
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pico-auth",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Minimal auth with user/pass, impersonation and mfa authentication",
|
|
5
|
+
"main": "dist/pico-auth.umd.js",
|
|
6
|
+
"types": "dist/pico-auth.d.ts",
|
|
7
|
+
"module": "dist/pico-auth.esm.min.js",
|
|
8
|
+
"homepage": "https://github.com/alkeicam/pico-auth",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/alkeicam/pico-auth/issues"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"impersonate",
|
|
14
|
+
"auth",
|
|
15
|
+
"mfa"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/pico-auth.d.ts",
|
|
21
|
+
"default": "./dist/pico-auth.umd.min.js"
|
|
22
|
+
},
|
|
23
|
+
"import": {
|
|
24
|
+
"types": "./dist/pico-auth.d.ts",
|
|
25
|
+
"default": "./dist/pico-auth.esm.min.js"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"clean": "rimraf dist/*",
|
|
31
|
+
"docs": "typedoc --entryPointStrategy expand ./src && touch docs/.nojekyll",
|
|
32
|
+
"build": "date && npm run clean && npm run build:js -s && npm run build:minjs -s && npm run build:types -s",
|
|
33
|
+
"build:js": "rollup -c rollup.config.js",
|
|
34
|
+
"build:minjs": "npm run build:minjs:esm -s && npm run build:minjs:umd -s",
|
|
35
|
+
"build:minjs:umd": "terser dist/pico-auth.umd.js --compress --mangle > dist/pico-auth.umd.min.js",
|
|
36
|
+
"build:minjs:esm": "terser dist/pico-auth.esm.js --compress --mangle > dist/pico-auth.esm.min.js",
|
|
37
|
+
"build:types": "tsc -t esnext --moduleResolution node -d --emitDeclarationOnly --outFile dist/pico-auth.d.ts src/pico-auth.ts",
|
|
38
|
+
"test": "env TS_NODE_PROJECT=\"tsconfig-test.json\" mocha -r ts-node/register --require source-map-support/register --recursive **/test/**/*.test.ts",
|
|
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"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"author": "Al Keicam",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"md5": "^2.3.0",
|
|
49
|
+
"speakeasy": "2.0.0",
|
|
50
|
+
"qrcode": "1.5.4",
|
|
51
|
+
"jsonwebtoken": "^8.5.1"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@rollup/plugin-typescript": "^6.1.0",
|
|
55
|
+
"@rollup/plugin-node-resolve": "15.2.3",
|
|
56
|
+
"@rollup/plugin-commonjs": "28.0.1",
|
|
57
|
+
"@types/chai": "4.2.14",
|
|
58
|
+
"@types/chai-as-promised": "7.1.3",
|
|
59
|
+
"@types/mocha": "8.0.3",
|
|
60
|
+
"@types/node": "20.5.0",
|
|
61
|
+
"@types/sinon": "9.0.8",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "4.6.1",
|
|
63
|
+
"@typescript-eslint/parser": "4.6.1",
|
|
64
|
+
"chai": "^3.5.0",
|
|
65
|
+
"chai-as-promised": "^6.0.0",
|
|
66
|
+
"eslint": "7.12.1",
|
|
67
|
+
"mocha": "^8.4.0",
|
|
68
|
+
"nyc": "14.1.x",
|
|
69
|
+
"prettier": "^2.8.8",
|
|
70
|
+
"pretty-quick": "^3.1.3",
|
|
71
|
+
"rollup": "^2.79.1",
|
|
72
|
+
"sinon": "^9.2.4",
|
|
73
|
+
"terser": "^5.19.2",
|
|
74
|
+
"ts-node": "10.8.2",
|
|
75
|
+
"tslib": "^2.6.2",
|
|
76
|
+
"typedoc": "^0.25.1",
|
|
77
|
+
"typescript": "^5.1.6",
|
|
78
|
+
"source-map-support": "^0.5.21",
|
|
79
|
+
"rimraf": "^5.0.5",
|
|
80
|
+
"shell-exec": "1.1.2"
|
|
81
|
+
},
|
|
82
|
+
"nyc": {
|
|
83
|
+
"check-coverage": true,
|
|
84
|
+
"branches": 100,
|
|
85
|
+
"lines": 100,
|
|
86
|
+
"functions": 100,
|
|
87
|
+
"statements": 100,
|
|
88
|
+
"extension": [
|
|
89
|
+
".ts",
|
|
90
|
+
".tsx"
|
|
91
|
+
],
|
|
92
|
+
"exclude": [
|
|
93
|
+
"**/*.d.ts",
|
|
94
|
+
"**/*.js",
|
|
95
|
+
"**/*.notest.ts",
|
|
96
|
+
"**/*.mock.ts",
|
|
97
|
+
"**/*.test.ts"
|
|
98
|
+
],
|
|
99
|
+
"all": true
|
|
100
|
+
}
|
|
101
|
+
}
|
package/readme.MD
ADDED