upgrade otplib to v13.4.1 #7702

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Jun 9, 2026 at 11:32 UTC b42bedfcaac70324656b0a0e00a8fd0ee76a7ff5
9 files changed +105 -67
dependencies.txt
+1 -1
@@ -10,7 +10,7 @@
10 "minimist": "1.2.8",
11 "multiparty": "4.3.0",
12 "node-forge": "1.4.0",
13 - "otplib": "12.0.1",
13 + "otplib": "13.4.1",
14 "ua-client-hints-js": "0.1.2",
15 "ua-parser-js": "1.0.40",
16 "ws": "8.21.0",
docker/Dockerfile
+1 -1
@@ -147,7 +147,7 @@ RUN case "$PREINSTALL_LIBS" in \
147 true|yes|TRUE|YES) \
148 cd meshcentral && \
149 echo -e "----------\nPREINSTALLING LIBRARIES...\n----------"; \
150 - npm install ssh2@1.17.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 otplib@12.0.1 yub@0.11.1;; \
150 + npm install ssh2@1.17.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 yub@0.11.1;; \
151 false|no|FALSE|NO) \
152 echo "Not pre-installing libraries.";; \
153 *) \
docker/Dockerfile-debian
+1 -1
@@ -183,7 +183,7 @@ RUN case "$PREINSTALL_LIBS" in \
183 true|yes|TRUE|YES) \
184 cd meshcentral && \
185 echo -e "----------\nPREINSTALLING LIBRARIES...\n----------"; \
186 - npm install ssh2@1.17.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 otplib@12.0.1 yub@0.11.1;; \
186 + npm install ssh2@1.17.0 nodemailer@6.10.1 image-size@2.0.2 wildleek@2.0.0 yub@0.11.1;; \
187 false|no|FALSE|NO) \
188 echo "Not pre-installing libraries.";; \
189 *) \
meshcentral.js
+1 -1
@@ -4397,7 +4397,7 @@ function mainStart() {
4397 if (config.settings.no2factorauth !== true) {
4398 // Setup YubiKey OTP if configured
4399 if (yubikey == true) { modules.push('yub@0.11.1'); } // Add YubiKey OTP support (replaced yubikeyotp due to form-data issues)
4400 - if (allsspi == false) { modules.push('otplib@12.0.1'); } // Google Authenticator support (v10 supports older NodeJS versions).
4400 + if (allsspi == false) { modules.push('otplib@13.4.1'); } // Google Authenticator support (v10 supports older NodeJS versions).
4401 }
4402
4403 // Desktop multiplexor support
meshuser.js
+11 -4
@@ -3763,7 +3763,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3763 var otplib = null;
3764 try { otplib = require('otplib'); } catch (ex) { }
3765 if (otplib == null) { ws.send(JSON.stringify({ action: 'otpauth-request', err: 6 })); return; }
3766 - const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value.
3766 + const secret = otplib.generateSecret(); // TODO: Check the random source of this value.
3767
3768 var domainName = parent.certificates.CommonName;
3769 if (domain.dns != null) {
@@ -3771,7 +3771,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3771 } else if (domain.dns == null && domain.id != '') {
3772 domainName += "/" + domain.id;
3773 }
3774 - ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(user.name, domainName, secret) }));
3774 + ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.generateURI({ issuer: domainName, label: user.name, secret: secret }) }));
3775 }
3776 break;
3777 }
@@ -3795,8 +3795,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3795 var otplib = null;
3796 try { otplib = require('otplib'); } catch (ex) { }
3797 if (otplib == null) { break; }
3798 - otplib.authenticator.options = { window: 2 }; // Set +/- 1 minute window
3799 - if (otplib.authenticator.check(command.token, command.secret) === true) {
3798 + const verified = require('otplib').verifySync({
3799 + epochTolerance: 60,
3800 + token: command.token,
3801 + secret: command.secret,
3802 + guardrails: otplib.createGuardrails({
3803 + MIN_SECRET_BYTES: 10, // https://github.com/yeojz/otplib/issues/671#issuecomment-4368647105
3804 + })
3805 + });
3806 + if (verified.valid === true) {
3807 // Token is valid, activate 2-step login on this account.
3808 user.otpsecret = command.secret;
3809 parent.db.SetUser(user);
package-lock.json
+73 -51
@@ -21,7 +21,7 @@
21 "minimist": "1.2.8",
22 "multiparty": "4.3.0",
23 "node-forge": "1.4.0",
24 - "otplib": "12.0.1",
24 + "otplib": "13.4.1",
25 "ua-client-hints-js": "0.1.2",
26 "ua-parser-js": "1.0.40",
27 "ws": "8.21.0",
@@ -51,54 +51,72 @@
51 "node": ">=12"
52 }
53 },
54 + "node_modules/@noble/hashes": {
55 + "version": "2.2.0",
56 + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz",
57 + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==",
58 + "license": "MIT",
59 + "engines": {
60 + "node": ">= 20.19.0"
61 + },
62 + "funding": {
63 + "url": "https://paulmillr.com/funding/"
64 + }
65 + },
66 "node_modules/@otplib/core": {
55 - "version": "12.0.1",
56 - "resolved": "https://registry.npmjs.org/@otplib/core/-/core-12.0.1.tgz",
57 - "integrity": "sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==",
67 + "version": "13.4.1",
68 + "resolved": "https://registry.npmjs.org/@otplib/core/-/core-13.4.1.tgz",
69 + "integrity": "sha512-KIXgK1hNtWJEBMTastbe1bpmuais+3f+ATeO8TkMs2rNkfGO1FbQy8+/UWVEu3TR/iTJerU0idkPudaPmLP2BA==",
70 "license": "MIT"
71 },
60 - "node_modules/@otplib/plugin-crypto": {
61 - "version": "12.0.1",
62 - "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz",
63 - "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==",
64 - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths",
72 + "node_modules/@otplib/hotp": {
73 + "version": "13.4.1",
74 + "resolved": "https://registry.npmjs.org/@otplib/hotp/-/hotp-13.4.1.tgz",
75 + "integrity": "sha512-g9q04SwpG5ZtMnVkUcgcoAlwCH4YLROZN1qhyBwgkBzqYYVSYhpP6gSGaxGHwePLt1c+e6NqDlgIZN+e1/XPuA==",
76 "license": "MIT",
77 "dependencies": {
67 - "@otplib/core": "^12.0.1"
78 + "@otplib/core": "13.4.1",
79 + "@otplib/uri": "13.4.1"
80 }
81 },
70 - "node_modules/@otplib/plugin-thirty-two": {
71 - "version": "12.0.1",
72 - "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz",
73 - "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==",
74 - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths",
82 + "node_modules/@otplib/plugin-base32-scure": {
83 + "version": "13.4.1",
84 + "resolved": "https://registry.npmjs.org/@otplib/plugin-base32-scure/-/plugin-base32-scure-13.4.1.tgz",
85 + "integrity": "sha512-Fs/r5qisC05SRhT6xWXaypB6PVC0vgWf6zztmi0J5RnQ09OJiPDWCJFH6cDm6ANsrdvB9di7X+Jb7L13BoEbUA==",
86 "license": "MIT",
87 "dependencies": {
77 - "@otplib/core": "^12.0.1",
78 - "thirty-two": "^1.0.2"
88 + "@otplib/core": "13.4.1",
89 + "@scure/base": "^2.2.0"
90 }
91 },
81 - "node_modules/@otplib/preset-default": {
82 - "version": "12.0.1",
83 - "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz",
84 - "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==",
85 - "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths",
92 + "node_modules/@otplib/plugin-crypto-noble": {
93 + "version": "13.4.1",
94 + "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto-noble/-/plugin-crypto-noble-13.4.1.tgz",
95 + "integrity": "sha512-PJfVW8/1hdS6CfxLheKPZSLTwDq4TijZbN4yRjxlv0ODdzmxpM+wGwWr1JXMdy0xJPxLziydQD5gdVqrR4/gAg==",
96 "license": "MIT",
97 "dependencies": {
88 - "@otplib/core": "^12.0.1",
89 - "@otplib/plugin-crypto": "^12.0.1",
90 - "@otplib/plugin-thirty-two": "^12.0.1"
98 + "@noble/hashes": "^2.2.0",
99 + "@otplib/core": "13.4.1"
100 }
101 },
93 - "node_modules/@otplib/preset-v11": {
94 - "version": "12.0.1",
95 - "resolved": "https://registry.npmjs.org/@otplib/preset-v11/-/preset-v11-12.0.1.tgz",
96 - "integrity": "sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg==",
102 + "node_modules/@otplib/totp": {
103 + "version": "13.4.1",
104 + "resolved": "https://registry.npmjs.org/@otplib/totp/-/totp-13.4.1.tgz",
105 + "integrity": "sha512-QOkBVPrf6AM4qZaReZPSk9/I8ATVdZpIISJz115MqeVtcrbcr5llPZ0J7804tpnjnp1vCRkI5Qjd47HhgVteBQ==",
106 "license": "MIT",
107 "dependencies": {
99 - "@otplib/core": "^12.0.1",
100 - "@otplib/plugin-crypto": "^12.0.1",
101 - "@otplib/plugin-thirty-two": "^12.0.1"
108 + "@otplib/core": "13.4.1",
109 + "@otplib/hotp": "13.4.1",
110 + "@otplib/uri": "13.4.1"
111 + }
112 + },
113 + "node_modules/@otplib/uri": {
114 + "version": "13.4.1",
115 + "resolved": "https://registry.npmjs.org/@otplib/uri/-/uri-13.4.1.tgz",
116 + "integrity": "sha512-xaIm7bvICMhoB2rZIR5luiaMdssWR5nY5nXnR1fdezUgZuEO58D6zrGzLp7pQuBmlpmL0HagnscDQFoskp9yiA==",
117 + "license": "MIT",
118 + "dependencies": {
119 + "@otplib/core": "13.4.1"
120 }
121 },
122 "node_modules/@pkgjs/parseargs": {
@@ -111,6 +129,15 @@
129 "node": ">=14"
130 }
131 },
132 + "node_modules/@scure/base": {
133 + "version": "2.2.0",
134 + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz",
135 + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==",
136 + "license": "MIT",
137 + "funding": {
138 + "url": "https://paulmillr.com/funding/"
139 + }
140 + },
141 "node_modules/@seald-io/binary-search-tree": {
142 "version": "1.0.3",
143 "resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.3.tgz",
@@ -1736,14 +1763,17 @@
1763 }
1764 },
1765 "node_modules/otplib": {
1739 - "version": "12.0.1",
1740 - "resolved": "https://registry.npmjs.org/otplib/-/otplib-12.0.1.tgz",
1741 - "integrity": "sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg==",
1766 + "version": "13.4.1",
1767 + "resolved": "https://registry.npmjs.org/otplib/-/otplib-13.4.1.tgz",
1768 + "integrity": "sha512-o5CxfDw6bh7hoDv0NUUIcc0RqzJ9ipfUrzeKheKJ+vs4rXZnDlA9n4a/7R1cDjpmLjKLix4BgNVRmoDkm5rLSQ==",
1769 "license": "MIT",
1770 "dependencies": {
1744 - "@otplib/core": "^12.0.1",
1745 - "@otplib/preset-default": "^12.0.1",
1746 - "@otplib/preset-v11": "^12.0.1"
1771 + "@otplib/core": "13.4.1",
1772 + "@otplib/hotp": "13.4.1",
1773 + "@otplib/plugin-base32-scure": "13.4.1",
1774 + "@otplib/plugin-crypto-noble": "13.4.1",
1775 + "@otplib/totp": "13.4.1",
1776 + "@otplib/uri": "13.4.1"
1777 }
1778 },
1779 "node_modules/package-json-from-dist": {
@@ -2053,14 +2083,14 @@
2083 }
2084 },
2085 "node_modules/side-channel": {
2056 - "version": "1.1.0",
2057 - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
2058 - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
2086 + "version": "1.1.1",
2087 + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
2088 + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
2089 "license": "MIT",
2090 "dependencies": {
2091 "es-errors": "^1.3.0",
2062 - "object-inspect": "^1.13.3",
2063 - "side-channel-list": "^1.0.0",
2092 + "object-inspect": "^1.13.4",
2093 + "side-channel-list": "^1.0.1",
2094 "side-channel-map": "^1.0.1",
2095 "side-channel-weakmap": "^1.0.2"
2096 },
@@ -2300,14 +2330,6 @@
2330 "b4a": "^1.6.4"
2331 }
2332 },
2303 - "node_modules/thirty-two": {
2304 - "version": "1.0.2",
2305 - "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz",
2306 - "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==",
2307 - "engines": {
2308 - "node": ">=0.2.6"
2309 - }
2310 - },
2333 "node_modules/toidentifier": {
2334 "version": "1.0.1",
2335 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
package.json
+1 -1
@@ -49,7 +49,7 @@
49 "minimist": "1.2.8",
50 "multiparty": "4.3.0",
51 "node-forge": "1.4.0",
52 - "otplib": "12.0.1",
52 + "otplib": "13.4.1",
53 "ua-client-hints-js": "0.1.2",
54 "ua-parser-js": "1.0.40",
55 "ws": "8.21.0",
reinstall-modules.bat
+1 -1
@@ -1 +1 @@
1 -npm install archiver authdog body-parser compression connect-redis cookie-session express express-handlebars express-ws ipcheck minimist mongojs multiparty nedb node-forge otplib ws xmldom yauzl yubikeyotp
\ No newline at end of file
1 +npm install archiver authdog compression connect-redis cookie-session express express-handlebars express-ws ipcheck minimist mongojs multiparty nedb node-forge otplib ws xmldom yauzl yubikeyotp
\ No newline at end of file
webserver.js
+15 -6
@@ -1110,12 +1110,21 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1110 }
1111
1112 // Check Google Authenticator
1113 - const otplib = require('otplib')
1114 - otplib.authenticator.options = { window: 2 }; // Set +/- 1 minute window
1115 - if (user.otpsecret && (typeof (token) == 'string') && (token.length == 6) && (otplib.authenticator.check(token, user.otpsecret) == true)) {
1116 - parent.debug('web', 'checkUserOneTimePassword: success (authenticator).');
1117 - func(true, { twoFactorType: 'otp' });
1118 - return;
1113 + if (user.otpsecret && (typeof (token) == 'string') && (token.length == 6)){
1114 + const otplib = require('otplib');
1115 + const verified = otplib.verifySync({
1116 + epochTolerance: 60,
1117 + token: token,
1118 + secret: user.otpsecret,
1119 + guardrails: otplib.createGuardrails({
1120 + MIN_SECRET_BYTES: 10, // https://github.com/yeojz/otplib/issues/671#issuecomment-4368647105
1121 + })
1122 + });
1123 + if (verified.valid === true) {
1124 + parent.debug('web', 'checkUserOneTimePassword: success (authenticator).');
1125 + func(true, { twoFactorType: 'otp' });
1126 + return;
1127 + }
1128 };
1129
1130 // Check written down keys