Registri gebaut
This commit is contained in:
parent
9aaf606758
commit
32ef5aa3b1
4
.env
4
.env
@ -7,4 +7,6 @@ DB_PASSWORD=RLR+2DHmZ6XJGotT2F7Ylrpdptc
|
|||||||
DB_NAME=dok
|
DB_NAME=dok
|
||||||
|
|
||||||
OFFLINE_SERVER_1=Test Server Alpha
|
OFFLINE_SERVER_1=Test Server Alpha
|
||||||
OFFLINE_SERVER_2=Test Server Beta
|
OFFLINE_SERVER_2=Test Server Beta
|
||||||
|
|
||||||
|
APP_URL=https://spiel.dynastyofknights.com
|
||||||
4
app.js
4
app.js
@ -6,6 +6,8 @@ const helmet = require("helmet");
|
|||||||
const rateLimit = require("express-rate-limit");
|
const rateLimit = require("express-rate-limit");
|
||||||
|
|
||||||
const serverRoutes = require("./routes/servers");
|
const serverRoutes = require("./routes/servers");
|
||||||
|
const registerRoutes = require("./routes/register");
|
||||||
|
const verifyRoutes = require("./routes/verify");
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
@ -48,6 +50,8 @@ app.use(express.static(path.join(__dirname, "public")));
|
|||||||
======================== */
|
======================== */
|
||||||
|
|
||||||
app.use("/", serverRoutes);
|
app.use("/", serverRoutes);
|
||||||
|
app.use("/register", registerRoutes);
|
||||||
|
app.use("/verify", verifyRoutes);
|
||||||
|
|
||||||
/* ========================
|
/* ========================
|
||||||
404 Handler
|
404 Handler
|
||||||
|
|||||||
16
node_modules/.bin/node-gyp-build
generated
vendored
Normal file
16
node_modules/.bin/node-gyp-build
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*)
|
||||||
|
if command -v cygpath > /dev/null 2>&1; then
|
||||||
|
basedir=`cygpath -w "$basedir"`
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
exec "$basedir/node" "$basedir/../node-gyp-build/bin.js" "$@"
|
||||||
|
else
|
||||||
|
exec node "$basedir/../node-gyp-build/bin.js" "$@"
|
||||||
|
fi
|
||||||
16
node_modules/.bin/node-gyp-build-optional
generated
vendored
Normal file
16
node_modules/.bin/node-gyp-build-optional
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*)
|
||||||
|
if command -v cygpath > /dev/null 2>&1; then
|
||||||
|
basedir=`cygpath -w "$basedir"`
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
exec "$basedir/node" "$basedir/../node-gyp-build/optional.js" "$@"
|
||||||
|
else
|
||||||
|
exec node "$basedir/../node-gyp-build/optional.js" "$@"
|
||||||
|
fi
|
||||||
17
node_modules/.bin/node-gyp-build-optional.cmd
generated
vendored
Normal file
17
node_modules/.bin/node-gyp-build-optional.cmd
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
GOTO start
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
||||||
|
:start
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\node-gyp-build\optional.js" %*
|
||||||
28
node_modules/.bin/node-gyp-build-optional.ps1
generated
vendored
Normal file
28
node_modules/.bin/node-gyp-build-optional.ps1
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "$basedir/node$exe" "$basedir/../node-gyp-build/optional.js" $args
|
||||||
|
} else {
|
||||||
|
& "$basedir/node$exe" "$basedir/../node-gyp-build/optional.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "node$exe" "$basedir/../node-gyp-build/optional.js" $args
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../node-gyp-build/optional.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
||||||
16
node_modules/.bin/node-gyp-build-test
generated
vendored
Normal file
16
node_modules/.bin/node-gyp-build-test
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*)
|
||||||
|
if command -v cygpath > /dev/null 2>&1; then
|
||||||
|
basedir=`cygpath -w "$basedir"`
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
exec "$basedir/node" "$basedir/../node-gyp-build/build-test.js" "$@"
|
||||||
|
else
|
||||||
|
exec node "$basedir/../node-gyp-build/build-test.js" "$@"
|
||||||
|
fi
|
||||||
17
node_modules/.bin/node-gyp-build-test.cmd
generated
vendored
Normal file
17
node_modules/.bin/node-gyp-build-test.cmd
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
GOTO start
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
||||||
|
:start
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\node-gyp-build\build-test.js" %*
|
||||||
28
node_modules/.bin/node-gyp-build-test.ps1
generated
vendored
Normal file
28
node_modules/.bin/node-gyp-build-test.ps1
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "$basedir/node$exe" "$basedir/../node-gyp-build/build-test.js" $args
|
||||||
|
} else {
|
||||||
|
& "$basedir/node$exe" "$basedir/../node-gyp-build/build-test.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "node$exe" "$basedir/../node-gyp-build/build-test.js" $args
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../node-gyp-build/build-test.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
||||||
17
node_modules/.bin/node-gyp-build.cmd
generated
vendored
Normal file
17
node_modules/.bin/node-gyp-build.cmd
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
GOTO start
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
||||||
|
:start
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\node-gyp-build\bin.js" %*
|
||||||
28
node_modules/.bin/node-gyp-build.ps1
generated
vendored
Normal file
28
node_modules/.bin/node-gyp-build.ps1
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "$basedir/node$exe" "$basedir/../node-gyp-build/bin.js" $args
|
||||||
|
} else {
|
||||||
|
& "$basedir/node$exe" "$basedir/../node-gyp-build/bin.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
# Support pipeline input
|
||||||
|
if ($MyInvocation.ExpectingInput) {
|
||||||
|
$input | & "node$exe" "$basedir/../node-gyp-build/bin.js" $args
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../node-gyp-build/bin.js" $args
|
||||||
|
}
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
||||||
50
node_modules/.package-lock.json
generated
vendored
50
node_modules/.package-lock.json
generated
vendored
@ -185,6 +185,29 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/bcrypt": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^8.3.0",
|
||||||
|
"node-gyp-build": "^4.8.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bcrypt/node_modules/node-addon-api": {
|
||||||
|
"version": "8.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz",
|
||||||
|
"integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || ^20 || >= 21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/better-sqlite3": {
|
"node_modules/better-sqlite3": {
|
||||||
"version": "12.6.2",
|
"version": "12.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz",
|
||||||
@ -483,6 +506,13 @@
|
|||||||
"node": ">=6.6.0"
|
"node": ">=6.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/crypto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
|
||||||
|
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/csrf": {
|
"node_modules/csrf": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz",
|
||||||
@ -1732,6 +1762,26 @@
|
|||||||
"node": ">= 10.12.0"
|
"node": ">= 10.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nodemailer": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-zbj002pZAIkWQFxyAaqoxvn+zoIwRnS40hgjqTXudKOOJkiFFgBeNqjgD3/YCR12sZnrghWYBY+yP1ZucdDRpw==",
|
||||||
|
"license": "MIT-0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nopt": {
|
"node_modules/nopt": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||||
|
|||||||
6
node_modules/bcrypt/.dockerignore
generated
vendored
Normal file
6
node_modules/bcrypt/.dockerignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.git/
|
||||||
|
.vscode/
|
||||||
|
Dockerfile*
|
||||||
|
prebuilds/
|
||||||
|
node_modules/
|
||||||
|
build*/
|
||||||
19
node_modules/bcrypt/.editorconfig
generated
vendored
Normal file
19
node_modules/bcrypt/.editorconfig
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{package.json,*.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[appveyor.yml]
|
||||||
|
end_of_line = crlf
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
110
node_modules/bcrypt/.github/workflows/build-pack-publish.yml
generated
vendored
Normal file
110
node_modules/bcrypt/.github/workflows/build-pack-publish.yml
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
name: Prebuildify, package, publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
release:
|
||||||
|
types: [ prereleased, released ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# This is unsafe, but we really don't use any other native dependencies
|
||||||
|
- run: npm ci
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/almalinux-devtoolset11 npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/alpine npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/linux-armv7 npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/linux-armv7l-musl npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/linux-arm64 npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: docker run -u $(id -u):$(id -g) -v `pwd`:/input -w /input ghcr.io/prebuild/linux-arm64-musl npx prebuildify --napi --tag-libc --strip --target=node@18.0.0
|
||||||
|
- run: find prebuilds
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: prebuild-linux
|
||||||
|
path: ./prebuilds/
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- run: npm ci
|
||||||
|
- run: npx prebuildify --napi --strip --arch=x64 --target=node@18.0.0
|
||||||
|
- run: npx prebuildify --napi --strip --arch=arm64 --target=node@20.0.0
|
||||||
|
- run: dir prebuilds
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: prebuild-windows
|
||||||
|
path: ./prebuilds/
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- run: npm ci
|
||||||
|
- run: npx prebuildify --napi --strip --arch=arm64 --target=node@18.0.0
|
||||||
|
- run: npx prebuildify --napi --strip --arch=x64 --target=node@18.0.0
|
||||||
|
- run: find prebuilds
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: prebuild-macos
|
||||||
|
path: ./prebuilds/
|
||||||
|
|
||||||
|
pack:
|
||||||
|
needs:
|
||||||
|
- build-linux
|
||||||
|
- build-windows
|
||||||
|
- build-macos
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
PACK_FILE: ${{ steps.pack.outputs.PACK_FILE }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: /tmp/prebuilds/
|
||||||
|
- name: Coalesce prebuilds from build matrix
|
||||||
|
run: |
|
||||||
|
mkdir prebuilds
|
||||||
|
for d in /tmp/prebuilds/*; do
|
||||||
|
cp -Rav $d/* prebuilds/
|
||||||
|
done
|
||||||
|
- run: chmod a+x prebuilds/*/*.node && find prebuilds -executable -type f
|
||||||
|
- id: pack
|
||||||
|
name: Prepare NPM package
|
||||||
|
run: |
|
||||||
|
echo "PACK_FILE=$(npm pack)" >> "$GITHUB_OUTPUT"
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: package-tgz
|
||||||
|
path: ${{ steps.pack.outputs.PACK_FILE }}
|
||||||
|
if-no-files-found: 'error'
|
||||||
|
|
||||||
|
test-package:
|
||||||
|
needs: pack
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [ 18, 20, 22, 23 ]
|
||||||
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: package-tgz
|
||||||
|
- run: npm install ${{ needs.pack.outputs.PACK_FILE }}
|
||||||
|
- run: node -e "const b = require('bcrypt'); const h = b.hashSync('hello', 10); console.log(h, b.compareSync('hello', h))"
|
||||||
42
node_modules/bcrypt/.github/workflows/ci.yaml
generated
vendored
Normal file
42
node_modules/bcrypt/.github/workflows/ci.yaml
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [18, 20, 22]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- run: npm ci
|
||||||
|
- name: Test
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
build-alpine:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [18, 20, 22]
|
||||||
|
container:
|
||||||
|
image: node:${{ matrix.node-version }}-alpine
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
apk add make g++ python3
|
||||||
|
- run: npm ci
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
npm test --unsafe-perm
|
||||||
184
node_modules/bcrypt/CHANGELOG.md
generated
vendored
Normal file
184
node_modules/bcrypt/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
# 6.0.0 (2025-02-28)
|
||||||
|
* Drop support for NodeJS <= 16
|
||||||
|
* Remove `node-pre-gyp` in favor of `prebuildify`, prebuilt binaries are now shipped with the package
|
||||||
|
* Update `node-addon-api` to 8.3.0
|
||||||
|
* Update JS code to newer ES syntax
|
||||||
|
|
||||||
|
# 5.1.0 (2022-10-06)
|
||||||
|
* Update `node-pre-gyp` to 1.0.11
|
||||||
|
|
||||||
|
# 5.1.0 (2022-10-06)
|
||||||
|
* Update `node-pre-gyp` to 1.0.10
|
||||||
|
* Replace `nodeunit` with `jest` as the testing library
|
||||||
|
|
||||||
|
# 5.0.1 (2021-02-22)
|
||||||
|
|
||||||
|
* Update `node-pre-gyp` to 1.0.0
|
||||||
|
|
||||||
|
# 5.0.0 (2020-06-02)
|
||||||
|
|
||||||
|
* Fix the bcrypt "wrap-around" bug. It affects passwords with lengths >= 255.
|
||||||
|
It is uncommon but it's a bug nevertheless. Previous attempts to fix the bug
|
||||||
|
was unsuccessful.
|
||||||
|
* Experimental support for z/OS
|
||||||
|
* Fix a bug related to NUL in password input
|
||||||
|
* Update `node-pre-gyp` to 0.15.0
|
||||||
|
|
||||||
|
# 4.0.1 (2020-02-27)
|
||||||
|
|
||||||
|
* Fix compilation errors in Alpine linux
|
||||||
|
|
||||||
|
# 4.0.0 (2020-02-17)
|
||||||
|
|
||||||
|
* Switch to NAPI bcrypt
|
||||||
|
* Drop support for NodeJS 8
|
||||||
|
|
||||||
|
# 3.0.8 (2019-12-31)
|
||||||
|
|
||||||
|
* Update `node-pre-gyp` to 0.14
|
||||||
|
* Pre-built binaries for NodeJS 13
|
||||||
|
|
||||||
|
# 3.0.7 (2019-10-18)
|
||||||
|
|
||||||
|
* Update `nan` to 2.14.0
|
||||||
|
* Update `node-pre-gyp` to 0.13
|
||||||
|
|
||||||
|
# 3.0.6 (2019-04-11)
|
||||||
|
|
||||||
|
* Update `nan` to 2.13.2
|
||||||
|
|
||||||
|
# 3.0.5 (2019-03-19)
|
||||||
|
|
||||||
|
* Update `nan` to 2.13.1
|
||||||
|
* NodeJS 12 compatibility
|
||||||
|
* Remove `node-pre-gyp` from bundled dependencies
|
||||||
|
|
||||||
|
# 3.0.4-napi (2019-03-08)
|
||||||
|
|
||||||
|
* Sync N-API bcrypt with NAN bcrypt
|
||||||
|
|
||||||
|
# 3.0.4 (2019-02-07)
|
||||||
|
|
||||||
|
* Fix GCC, NAN and V8 deprecation warnings
|
||||||
|
|
||||||
|
# 3.0.3 (2018-12-19)
|
||||||
|
|
||||||
|
* Update `nan` to 2.12.1
|
||||||
|
|
||||||
|
# 3.0.2 (2018-10-18)
|
||||||
|
|
||||||
|
* Update `nan` to 2.11.1
|
||||||
|
|
||||||
|
# 3.0.1 (2018-09-20)
|
||||||
|
|
||||||
|
* Update `nan` to 2.11.0
|
||||||
|
|
||||||
|
# 3.0.0 (2018-07-06)
|
||||||
|
|
||||||
|
* Drop support for NodeJS <= 4
|
||||||
|
|
||||||
|
# 2.0.1 (2018-04-20)
|
||||||
|
|
||||||
|
* Update `node-pre-gyp` to allow downloading prebuilt modules
|
||||||
|
|
||||||
|
# 2.0.0 (2018-04-07)
|
||||||
|
|
||||||
|
* Make `2b` the default bcrypt version
|
||||||
|
|
||||||
|
# 1.1.0-napi (2018-01-21)
|
||||||
|
|
||||||
|
* Initial support for [N-API](https://nodejs.org/api/n-api.html)
|
||||||
|
|
||||||
|
# 1.0.3 (2016-08-23)
|
||||||
|
|
||||||
|
* update to nan v2.6.2 for NodeJS 8 support
|
||||||
|
* Fix: use npm scripts instead of node-gyp directly.
|
||||||
|
|
||||||
|
# 1.0.2 (2016-12-31)
|
||||||
|
|
||||||
|
* Fix `compare` promise rejection with invalid arguments
|
||||||
|
|
||||||
|
# 1.0.1 (2016-12-07)
|
||||||
|
|
||||||
|
* Fix destructuring imports with promises
|
||||||
|
|
||||||
|
# 1.0.0 (2016-12-04)
|
||||||
|
|
||||||
|
* add Promise support (commit 2488473)
|
||||||
|
|
||||||
|
# 0.8.7 (2016-06-09)
|
||||||
|
|
||||||
|
* update nan to 2.3.5 for improved node v6 support
|
||||||
|
|
||||||
|
# 0.8.6 (2016-04-20)
|
||||||
|
|
||||||
|
* update nan for node v6 support
|
||||||
|
|
||||||
|
# 0.8.5 (2015-08-12)
|
||||||
|
|
||||||
|
* update to nan v2 (adds support for iojs 3)
|
||||||
|
|
||||||
|
# 0.8.4 (2015-07-24)
|
||||||
|
|
||||||
|
* fix deprecation warning for the Encode API
|
||||||
|
|
||||||
|
# 0.8.3 (2015-05-06)
|
||||||
|
|
||||||
|
* update nan to 1.8.4 for iojs 2.x support
|
||||||
|
|
||||||
|
# 0.8.2 (2015-03-28)
|
||||||
|
|
||||||
|
* always use callback for generating random bytes to avoid blocking
|
||||||
|
|
||||||
|
# 0.8.1 (2015-01-18)
|
||||||
|
* update NaN to 1.5.0 for iojs support
|
||||||
|
|
||||||
|
# 0.8.0 (2014-08-03)
|
||||||
|
* migrate to NAN for bindings
|
||||||
|
|
||||||
|
# v0.5.0
|
||||||
|
* Fix for issue around empty string params throwing Errors.
|
||||||
|
* Method deprecation.
|
||||||
|
* Upgrade from libeio/ev to libuv. (shtylman)
|
||||||
|
** --- NOTE --- Breaks 0.4.x compatability
|
||||||
|
* EV_MULTIPLICITY compile flag.
|
||||||
|
|
||||||
|
# v0.4.1
|
||||||
|
* Thread safety fix around OpenSSL (GH-32). (bnoordhuis - through node)
|
||||||
|
* C++ code changes using delete and new instead of malloc and free. (shtylman)
|
||||||
|
* Compile options for speed, zoom. (shtylman)
|
||||||
|
* Move much of the type and variable checking to the JS. (shtylman)
|
||||||
|
|
||||||
|
# v0.4.0
|
||||||
|
* Added getRounds function that will tell you the number of rounds within a hash/salt
|
||||||
|
|
||||||
|
# v0.3.2
|
||||||
|
* Fix api issue with async salt gen first param
|
||||||
|
|
||||||
|
# v0.3.1
|
||||||
|
* Compile under node 0.5.x
|
||||||
|
|
||||||
|
# v0.3.0
|
||||||
|
* Internal Refactoring
|
||||||
|
* Remove pthread dependencies and locking
|
||||||
|
* Fix compiler warnings and a memory bug
|
||||||
|
|
||||||
|
# v0.2.4
|
||||||
|
* Use threadsafe functions instead of pthread mutexes
|
||||||
|
* salt validation to make sure the salt is of the correct size and format
|
||||||
|
|
||||||
|
# v0.2.3
|
||||||
|
* cygwin support
|
||||||
|
|
||||||
|
# v0.2.2
|
||||||
|
* Remove dependency on libbsd, use libssl instead
|
||||||
|
|
||||||
|
# v0.2.0
|
||||||
|
* Added async functionality
|
||||||
|
* API changes
|
||||||
|
* hashpw -> encrypt
|
||||||
|
* all old sync methods now end with _sync
|
||||||
|
* Removed libbsd(arc4random) dependency...now uses openssl which is more widely spread
|
||||||
|
|
||||||
|
# v0.1.2
|
||||||
|
* Security fix. Wasn't reading rounds in properly and was always only using 4 rounds
|
||||||
57
node_modules/bcrypt/Dockerfile
generated
vendored
Normal file
57
node_modules/bcrypt/Dockerfile
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# docker build -t bcryptjs-builder .
|
||||||
|
# CONTAINER=$(docker create bcryptjs-builder)
|
||||||
|
# # Then copy the artifact to your host:
|
||||||
|
# docker cp "$CONTAINER:/usr/local/opt/bcrypt-js/prebuilds" .
|
||||||
|
# docker rm "$CONTAINER"
|
||||||
|
#
|
||||||
|
# Use --platform to build cross-platform i.e. for ARM:
|
||||||
|
#
|
||||||
|
# docker build -t bcryptjs-builder --platform "linux/arm64/v8" .
|
||||||
|
# CONTAINER=$docker create --platform "linux/arm64/v8" bcryptjs-builder)
|
||||||
|
# # this copies the prebuilds/linux-arm artifacts
|
||||||
|
# docker cp "$CONTAINER:/usr/local/opt/bcrypt-js/prebuilds" .
|
||||||
|
# docker rm "$CONTAINER"
|
||||||
|
|
||||||
|
|
||||||
|
ARG FROM_IMAGE=node:18-bullseye
|
||||||
|
#ARG FROM_IMAGE=arm32v7/node:16-bullseye
|
||||||
|
#ARG FROM_IMAGE=arm64v8/node:16-bullseye
|
||||||
|
FROM ${FROM_IMAGE}
|
||||||
|
|
||||||
|
ENV project bcrypt-js
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV LC_ALL en_US.UTF-8
|
||||||
|
ENV LANG ${LC_ALL}
|
||||||
|
|
||||||
|
RUN echo "#log: ${project}: Setup system" \
|
||||||
|
&& set -x \
|
||||||
|
&& apt-get update -y \
|
||||||
|
&& apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
python3 \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& update-alternatives --install /usr/local/bin/python python /usr/bin/python3 20 \
|
||||||
|
&& npm i -g prebuildify@5 node-gyp@9 \
|
||||||
|
&& sync
|
||||||
|
|
||||||
|
ADD . /usr/local/opt/${project}
|
||||||
|
WORKDIR /usr/local/opt/${project}
|
||||||
|
|
||||||
|
RUN echo "#log: ${project}: Running build" \
|
||||||
|
&& set -x \
|
||||||
|
&& npm ci \
|
||||||
|
&& npm run build
|
||||||
|
|
||||||
|
ARG RUN_TESTS=true
|
||||||
|
ARG TEST_TIMEOUT_SECONDS=
|
||||||
|
|
||||||
|
RUN if "${RUN_TESTS}"; then \
|
||||||
|
echo "#log ${project}: Running tests" \
|
||||||
|
&& npm test; \
|
||||||
|
else \
|
||||||
|
echo "#log ${project}: Tests were skipped!"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
CMD /bin/bash -l
|
||||||
41
node_modules/bcrypt/Dockerfile-alpine
generated
vendored
Normal file
41
node_modules/bcrypt/Dockerfile-alpine
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# docker build -t bcryptjs-linux-alpine-builder -f Dockerfile-alpine .
|
||||||
|
# CONTAINER=$(docker create bcryptjs-linux-alpine-builder)
|
||||||
|
# # Then copy the artifact to your host:
|
||||||
|
# docker cp "$CONTAINER:/usr/local/opt/bcrypt-js/prebuilds" .
|
||||||
|
# docker rm "$CONTAINER"
|
||||||
|
|
||||||
|
ARG FROM_IMAGE=node:18-alpine
|
||||||
|
FROM ${FROM_IMAGE}
|
||||||
|
|
||||||
|
ENV project bcrypt-js
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV LC_ALL en_US.UTF-8
|
||||||
|
ENV LANG ${LC_ALL}
|
||||||
|
|
||||||
|
RUN echo "#log: ${project}: Setup system" \
|
||||||
|
&& set -x \
|
||||||
|
&& apk add --update build-base python3 \
|
||||||
|
&& npm i -g prebuildify@5 node-gyp@9 \
|
||||||
|
&& sync
|
||||||
|
|
||||||
|
ADD . /usr/local/opt/${project}
|
||||||
|
WORKDIR /usr/local/opt/${project}
|
||||||
|
|
||||||
|
RUN echo "#log: ${project}: Running build" \
|
||||||
|
&& set -x \
|
||||||
|
&& npm ci \
|
||||||
|
&& npm run build
|
||||||
|
|
||||||
|
ARG RUN_TESTS=true
|
||||||
|
ARG TEST_TIMEOUT_SECONDS=
|
||||||
|
|
||||||
|
RUN if "${RUN_TESTS}"; then \
|
||||||
|
echo "#log ${project}: Running tests" \
|
||||||
|
&& npm test; \
|
||||||
|
else \
|
||||||
|
echo "#log ${project}: Tests were skipped!"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
CMD /bin/bash -l
|
||||||
18
node_modules/bcrypt/ISSUE_TEMPLATE.md
generated
vendored
Normal file
18
node_modules/bcrypt/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Thanks for reporting a new issue with the node bcrypt module!
|
||||||
|
|
||||||
|
To help you resolve your issue faster please make sure you have done the following:
|
||||||
|
|
||||||
|
* Searched existing issues (even closed ones) for your same problem
|
||||||
|
* Make sure you have installed the required dependencies listed on the readme
|
||||||
|
* Read your npm error log for lines telling you what failed, usually it is a problem with not having the correct dependencies installed to build the native module
|
||||||
|
|
||||||
|
Once you have done the above and are still confident that the issue is with the module, please describe it below. Some things that really help get your issue resolved faster are:
|
||||||
|
|
||||||
|
* What went wrong?
|
||||||
|
* What did you expect to happen?
|
||||||
|
* Which version of nodejs and OS?
|
||||||
|
* If you find a bug, please write a failing test.
|
||||||
|
|
||||||
|
Thanks!
|
||||||
|
|
||||||
|
P.S. If it doesn't look like you read the above then your issue will likely be closed without further explanation. Sorry, but there are just too many issues opened with no useful information or questions which have been previously addressed.
|
||||||
19
node_modules/bcrypt/LICENSE
generated
vendored
Normal file
19
node_modules/bcrypt/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2010 Nicholas Campbell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
19
node_modules/bcrypt/Makefile
generated
vendored
Normal file
19
node_modules/bcrypt/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
TESTS = test/*.js
|
||||||
|
|
||||||
|
all: test
|
||||||
|
|
||||||
|
build: clean compile
|
||||||
|
|
||||||
|
compile:
|
||||||
|
npm install .
|
||||||
|
npm run install
|
||||||
|
|
||||||
|
test: build
|
||||||
|
@./node_modules/.bin/jest \
|
||||||
|
$(TESTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -Rf lib/bindings/
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean test build
|
||||||
388
node_modules/bcrypt/README.md
generated
vendored
Normal file
388
node_modules/bcrypt/README.md
generated
vendored
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
# node.bcrypt.js
|
||||||
|
|
||||||
|
[](https://github.com/kelektiv/node.bcrypt.js/actions/workflows/ci.yaml)
|
||||||
|
|
||||||
|
[](https://ci.appveyor.com/project/defunctzombie/node-bcrypt-js-pgo26/branch/master)
|
||||||
|
|
||||||
|
A library to help you hash passwords.
|
||||||
|
|
||||||
|
You can read about [bcrypt in Wikipedia][bcryptwiki] as well as in the following article:
|
||||||
|
[How To Safely Store A Password][codahale]
|
||||||
|
|
||||||
|
## If You Are Submitting Bugs or Issues
|
||||||
|
|
||||||
|
Please verify that the NodeJS version you are using is a _stable_ version; Unstable versions are currently not supported and issues created while using an unstable version will be closed.
|
||||||
|
|
||||||
|
If you are on a stable version of NodeJS, please provide a sufficient code snippet or log files for installation issues. The code snippet does not require you to include confidential information. However, it must provide enough information so the problem can be replicable, or it may be closed without an explanation.
|
||||||
|
|
||||||
|
|
||||||
|
## Version Compatibility
|
||||||
|
|
||||||
|
_Please upgrade to atleast v5.0.0 to avoid security issues mentioned below._
|
||||||
|
|
||||||
|
| Node Version | Bcrypt Version |
|
||||||
|
| -------------- | ------------------|
|
||||||
|
| 0.4 | <= 0.4 |
|
||||||
|
| 0.6, 0.8, 0.10 | >= 0.5 |
|
||||||
|
| 0.11 | >= 0.8 |
|
||||||
|
| 4 | <= 2.1.0 |
|
||||||
|
| 8 | >= 1.0.3 < 4.0.0 |
|
||||||
|
| 10, 11 | >= 3 |
|
||||||
|
| 12 onwards | >= 3.0.6 |
|
||||||
|
|
||||||
|
`node-gyp` only works with stable/released versions of node. Since the `bcrypt` module uses `node-gyp` to build and install, you'll need a stable version of node to use bcrypt. If you do not, you'll likely see an error that starts with:
|
||||||
|
|
||||||
|
```
|
||||||
|
gyp ERR! stack Error: "pre" versions of node cannot be installed, use the --nodedir flag instead
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Issues And Concerns
|
||||||
|
|
||||||
|
> Per bcrypt implementation, only the first 72 bytes of a string are used. Any extra bytes are ignored when matching passwords. Note that this is not the first 72 *characters*. It is possible for a string to contain less than 72 characters, while taking up more than 72 bytes (e.g. a UTF-8 encoded string containing emojis). If a string is provided, it will be encoded using UTF-8.
|
||||||
|
|
||||||
|
As should be the case with any security tool, anyone using this library should scrutinise it. If you find or suspect an issue with the code, please bring it to the maintainers' attention. We will spend some time ensuring that this library is as secure as possible.
|
||||||
|
|
||||||
|
Here is a list of BCrypt-related security issues/concerns that have come up over the years.
|
||||||
|
|
||||||
|
* An [issue with passwords][jtr] was found with a version of the Blowfish algorithm developed for John the Ripper. This is not present in the OpenBSD version and is thus not a problem for this module. HT [zooko][zooko].
|
||||||
|
* Versions `< 5.0.0` suffer from bcrypt wrap-around bug and _will truncate passwords >= 255 characters leading to severely weakened passwords_. Please upgrade at earliest. See [this wiki page][wrap-around-bug] for more details.
|
||||||
|
* Versions `< 5.0.0` _do not handle NUL characters inside passwords properly leading to all subsequent characters being dropped and thus resulting in severely weakened passwords_. Please upgrade at earliest. See [this wiki page][improper-nuls] for more details.
|
||||||
|
|
||||||
|
## Compatibility Note
|
||||||
|
|
||||||
|
This library supports `$2a$` and `$2b$` prefix bcrypt hashes. `$2x$` and `$2y$` hashes are specific to bcrypt implementation developed for John the Ripper. In theory, they should be compatible with `$2b$` prefix.
|
||||||
|
|
||||||
|
Compatibility with hashes generated by other languages is not 100% guaranteed due to difference in character encodings. However, it should not be an issue for most cases.
|
||||||
|
|
||||||
|
### Migrating from v1.0.x
|
||||||
|
|
||||||
|
Hashes generated in earlier version of `bcrypt` remain 100% supported in `v2.x.x` and later versions. In most cases, the migration should be a bump in the `package.json`.
|
||||||
|
|
||||||
|
Hashes generated in `v2.x.x` using the defaults parameters will not work in earlier versions.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
* NodeJS
|
||||||
|
* `node-gyp`
|
||||||
|
* Please check the dependencies for this tool at: https://github.com/nodejs/node-gyp
|
||||||
|
* Windows users will need the options for c# and c++ installed with their visual studio instance.
|
||||||
|
* Python 2.x/3.x
|
||||||
|
* `OpenSSL` - This is only required to build the `bcrypt` project if you are using versions <= 0.7.7. Otherwise, we're using the builtin node crypto bindings for seed data (which use the same OpenSSL code paths we were, but don't have the external dependency).
|
||||||
|
|
||||||
|
## Install via NPM
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install bcrypt
|
||||||
|
```
|
||||||
|
***Note:*** OS X users using Xcode 4.3.1 or above may need to run the following command in their terminal prior to installing if errors occur regarding xcodebuild: ```sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer```
|
||||||
|
|
||||||
|
_Pre-built binaries for various NodeJS versions are made available on a best-effort basis._
|
||||||
|
|
||||||
|
Only the current stable and supported LTS releases are actively tested against.
|
||||||
|
|
||||||
|
_There may be an interval between the release of the module and the availabilty of the compiled modules._
|
||||||
|
|
||||||
|
Currently, we have pre-built binaries that support the following platforms:
|
||||||
|
|
||||||
|
1. Windows x32 and x64
|
||||||
|
2. Linux x64 (GlibC and musl)
|
||||||
|
3. macOS
|
||||||
|
|
||||||
|
If you face an error like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v48-linux-x64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
make sure you have the appropriate dependencies installed and configured for your platform. You can find installation instructions for the dependencies for some common platforms [in this page][depsinstall].
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### async (recommended)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const bcrypt = require('bcrypt');
|
||||||
|
const saltRounds = 10;
|
||||||
|
const myPlaintextPassword = 's0/\/\P4$$w0rD';
|
||||||
|
const someOtherPlaintextPassword = 'not_bacon';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### To hash a password:
|
||||||
|
|
||||||
|
Technique 1 (generate a salt and hash on separate function calls):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
bcrypt.genSalt(saltRounds, function(err, salt) {
|
||||||
|
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
|
||||||
|
// Store hash in your password DB.
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Technique 2 (auto-gen a salt and hash):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
|
||||||
|
// Store hash in your password DB.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that both techniques achieve the same end-result.
|
||||||
|
|
||||||
|
#### To check a password:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Load hash from your password DB.
|
||||||
|
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
|
||||||
|
// result == true
|
||||||
|
});
|
||||||
|
bcrypt.compare(someOtherPlaintextPassword, hash, function(err, result) {
|
||||||
|
// result == false
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
[A Note on Timing Attacks](#a-note-on-timing-attacks)
|
||||||
|
|
||||||
|
### with promises
|
||||||
|
|
||||||
|
bcrypt uses whatever `Promise` implementation is available in `global.Promise`. NodeJS >= 0.12 has a native `Promise` implementation built in. However, this should work in any Promises/A+ compliant implementation.
|
||||||
|
|
||||||
|
Async methods that accept a callback, return a `Promise` when callback is not specified if Promise support is available.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
bcrypt.hash(myPlaintextPassword, saltRounds).then(function(hash) {
|
||||||
|
// Store hash in your password DB.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
// Load hash from your password DB.
|
||||||
|
bcrypt.compare(myPlaintextPassword, hash).then(function(result) {
|
||||||
|
// result == true
|
||||||
|
});
|
||||||
|
bcrypt.compare(someOtherPlaintextPassword, hash).then(function(result) {
|
||||||
|
// result == false
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This is also compatible with `async/await`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function checkUser(username, password) {
|
||||||
|
//... fetch user from a db etc.
|
||||||
|
|
||||||
|
const match = await bcrypt.compare(password, user.passwordHash);
|
||||||
|
|
||||||
|
if(match) {
|
||||||
|
//login
|
||||||
|
}
|
||||||
|
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ESM import
|
||||||
|
```javascript
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
|
||||||
|
// later
|
||||||
|
await bcrypt.compare(password, hash);
|
||||||
|
```
|
||||||
|
|
||||||
|
### sync
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const bcrypt = require('bcrypt');
|
||||||
|
const saltRounds = 10;
|
||||||
|
const myPlaintextPassword = 's0/\/\P4$$w0rD';
|
||||||
|
const someOtherPlaintextPassword = 'not_bacon';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### To hash a password:
|
||||||
|
|
||||||
|
Technique 1 (generate a salt and hash on separate function calls):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const salt = bcrypt.genSaltSync(saltRounds);
|
||||||
|
const hash = bcrypt.hashSync(myPlaintextPassword, salt);
|
||||||
|
// Store hash in your password DB.
|
||||||
|
```
|
||||||
|
|
||||||
|
Technique 2 (auto-gen a salt and hash):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
|
||||||
|
// Store hash in your password DB.
|
||||||
|
```
|
||||||
|
|
||||||
|
As with async, both techniques achieve the same end-result.
|
||||||
|
|
||||||
|
#### To check a password:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Load hash from your password DB.
|
||||||
|
bcrypt.compareSync(myPlaintextPassword, hash); // true
|
||||||
|
bcrypt.compareSync(someOtherPlaintextPassword, hash); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
[A Note on Timing Attacks](#a-note-on-timing-attacks)
|
||||||
|
|
||||||
|
### Why is async mode recommended over sync mode?
|
||||||
|
We recommend using async API if you use `bcrypt` on a server. Bcrypt hashing is CPU intensive which will cause the sync APIs to block the event loop and prevent your application from servicing any inbound requests or events. The async version uses a thread pool which does not block the main event loop.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
`BCrypt.`
|
||||||
|
|
||||||
|
* `genSaltSync(rounds, minor)`
|
||||||
|
* `rounds` - [OPTIONAL] - the cost of processing the data. (default - 10)
|
||||||
|
* `minor` - [OPTIONAL] - minor version of bcrypt to use. (default - b)
|
||||||
|
* `genSalt(rounds, minor, cb)`
|
||||||
|
* `rounds` - [OPTIONAL] - the cost of processing the data. (default - 10)
|
||||||
|
* `minor` - [OPTIONAL] - minor version of bcrypt to use. (default - b)
|
||||||
|
* `cb` - [OPTIONAL] - a callback to be fired once the salt has been generated. uses eio making it asynchronous. If `cb` is not specified, a `Promise` is returned if Promise support is available.
|
||||||
|
* `err` - First parameter to the callback detailing any errors.
|
||||||
|
* `salt` - Second parameter to the callback providing the generated salt.
|
||||||
|
* `hashSync(data, salt)`
|
||||||
|
* `data` - [REQUIRED] - the data to be encrypted.
|
||||||
|
* `salt` - [REQUIRED] - the salt to be used to hash the password. if specified as a number then a salt will be generated with the specified number of rounds and used (see example under **Usage**).
|
||||||
|
* `hash(data, salt, cb)`
|
||||||
|
* `data` - [REQUIRED] - the data to be encrypted.
|
||||||
|
* `salt` - [REQUIRED] - the salt to be used to hash the password. if specified as a number then a salt will be generated with the specified number of rounds and used (see example under **Usage**).
|
||||||
|
* `cb` - [OPTIONAL] - a callback to be fired once the data has been encrypted. uses eio making it asynchronous. If `cb` is not specified, a `Promise` is returned if Promise support is available.
|
||||||
|
* `err` - First parameter to the callback detailing any errors.
|
||||||
|
* `encrypted` - Second parameter to the callback providing the encrypted form.
|
||||||
|
* `compareSync(data, encrypted)`
|
||||||
|
* `data` - [REQUIRED] - data to compare.
|
||||||
|
* `encrypted` - [REQUIRED] - data to be compared to.
|
||||||
|
* `compare(data, encrypted, cb)`
|
||||||
|
* `data` - [REQUIRED] - data to compare.
|
||||||
|
* `encrypted` - [REQUIRED] - data to be compared to.
|
||||||
|
* `cb` - [OPTIONAL] - a callback to be fired once the data has been compared. uses eio making it asynchronous. If `cb` is not specified, a `Promise` is returned if Promise support is available.
|
||||||
|
* `err` - First parameter to the callback detailing any errors.
|
||||||
|
* `same` - Second parameter to the callback providing whether the data and encrypted forms match [true | false].
|
||||||
|
* `getRounds(encrypted)` - return the number of rounds used to encrypt a given hash
|
||||||
|
* `encrypted` - [REQUIRED] - hash from which the number of rounds used should be extracted.
|
||||||
|
|
||||||
|
## A Note on Rounds
|
||||||
|
|
||||||
|
A note about the cost: when you are hashing your data, the module will go through a series of rounds to give you a secure hash. The value you submit is not just the number of rounds the module will go through to hash your data. The module will use the value you enter and go through `2^rounds` hashing iterations.
|
||||||
|
|
||||||
|
From @garthk, on a 2GHz core you can roughly expect:
|
||||||
|
|
||||||
|
rounds=8 : ~40 hashes/sec
|
||||||
|
rounds=9 : ~20 hashes/sec
|
||||||
|
rounds=10: ~10 hashes/sec
|
||||||
|
rounds=11: ~5 hashes/sec
|
||||||
|
rounds=12: 2-3 hashes/sec
|
||||||
|
rounds=13: ~1 sec/hash
|
||||||
|
rounds=14: ~1.5 sec/hash
|
||||||
|
rounds=15: ~3 sec/hash
|
||||||
|
rounds=25: ~1 hour/hash
|
||||||
|
rounds=31: 2-3 days/hash
|
||||||
|
|
||||||
|
|
||||||
|
## A Note on Timing Attacks
|
||||||
|
|
||||||
|
Because it's come up multiple times in this project and other bcrypt projects, it needs to be said. The `bcrypt` library is not susceptible to timing attacks. From codahale/bcrypt-ruby#42:
|
||||||
|
|
||||||
|
> One of the desired properties of a cryptographic hash function is preimage attack resistance, which means there is no shortcut for generating a message which, when hashed, produces a specific digest.
|
||||||
|
|
||||||
|
A great thread on this, in much more detail can be found @ codahale/bcrypt-ruby#43
|
||||||
|
|
||||||
|
If you're unfamiliar with timing attacks and want to learn more you can find a great writeup @ [A Lesson In Timing Attacks][timingatk]
|
||||||
|
|
||||||
|
However, timing attacks are real. And the comparison function is _not_ time safe. That means that it may exit the function early in the comparison process. Timing attacks happen because of the above. We don't need to be careful that an attacker will learn anything, and our comparison function provides a comparison of hashes. It is a utility to the overall purpose of the library. If you end up using it for something else, we cannot guarantee the security of the comparator. Keep that in mind as you use the library.
|
||||||
|
|
||||||
|
## Hash Info
|
||||||
|
|
||||||
|
The characters that comprise the resultant hash are `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$`.
|
||||||
|
|
||||||
|
Resultant hashes will be 60 characters long and they will include the salt among other parameters, as follows:
|
||||||
|
|
||||||
|
`$[algorithm]$[cost]$[salt][hash]`
|
||||||
|
|
||||||
|
- 2 chars hash algorithm identifier prefix. `"$2a$" or "$2b$"` indicates BCrypt
|
||||||
|
- Cost-factor (n). Represents the exponent used to determine how many iterations 2^n
|
||||||
|
- 16-byte (128-bit) salt, base64 encoded to 22 characters
|
||||||
|
- 24-byte (192-bit) hash, base64 encoded to 31 characters
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
$2b$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
|
||||||
|
| | | |
|
||||||
|
| | | hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
|
||||||
|
| | |
|
||||||
|
| | salt = nOUIs5kJ7naTuTFkBy1veu
|
||||||
|
| |
|
||||||
|
| cost-factor => 10 = 2^10 rounds
|
||||||
|
|
|
||||||
|
hash-algorithm identifier => 2b = BCrypt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
If you create a pull request, tests better pass :)
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
The code for this comes from a few sources:
|
||||||
|
|
||||||
|
* blowfish.cc - OpenBSD
|
||||||
|
* bcrypt.cc - OpenBSD
|
||||||
|
* bcrypt::gen_salt - [gen_salt inclusion to bcrypt][bcryptgs]
|
||||||
|
* bcrypt_node.cc - me
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
* [Antonio Salazar Cardozo][shadowfiend] - Early MacOS X support (when we used libbsd)
|
||||||
|
* [Ben Glow][pixelglow] - Fixes for thread safety with async calls
|
||||||
|
* [Van Nguyen][thegoleffect] - Found a timing attack in the comparator
|
||||||
|
* [NewITFarmer][newitfarmer] - Initial Cygwin support
|
||||||
|
* [David Trejo][dtrejo] - packaging fixes
|
||||||
|
* [Alfred Westerveld][alfredwesterveld] - packaging fixes
|
||||||
|
* [Vincent Côté-Roy][vincentr] - Testing around concurrency issues
|
||||||
|
* [Lloyd Hilaiel][lloyd] - Documentation fixes
|
||||||
|
* [Roman Shtylman][shtylman] - Code refactoring, general rot reduction, compile options, better memory management with delete and new, and an upgrade to libuv over eio/ev.
|
||||||
|
* [Vadim Graboys][vadimg] - Code changes to support 0.5.5+
|
||||||
|
* [Ben Noordhuis][bnoordhuis] - Fixed a thread safety issue in nodejs that was perfectly mappable to this module.
|
||||||
|
* [Nate Rajlich][tootallnate] - Bindings and build process.
|
||||||
|
* [Sean McArthur][seanmonstar] - Windows Support
|
||||||
|
* [Fanie Oosthuysen][weareu] - Windows Support
|
||||||
|
* [Amitosh Swain Mahapatra][recrsn] - $2b$ hash support, ES6 Promise support
|
||||||
|
* [Nicola Del Gobbo][NickNaso] - Initial implementation with N-API
|
||||||
|
|
||||||
|
## License
|
||||||
|
Unless stated elsewhere, file headers or otherwise, the license as stated in the LICENSE file.
|
||||||
|
|
||||||
|
[bcryptwiki]: https://en.wikipedia.org/wiki/Bcrypt
|
||||||
|
[bcryptgs]: http://mail-index.netbsd.org/tech-crypto/2002/05/24/msg000204.html
|
||||||
|
[codahale]: http://codahale.com/how-to-safely-store-a-password/
|
||||||
|
[gh13]: https://github.com/ncb000gt/node.bcrypt.js/issues/13
|
||||||
|
[jtr]: http://www.openwall.com/lists/oss-security/2011/06/20/2
|
||||||
|
[depsinstall]: https://github.com/kelektiv/node.bcrypt.js/wiki/Installation-Instructions
|
||||||
|
[timingatk]: https://codahale.com/a-lesson-in-timing-attacks/
|
||||||
|
[wrap-around-bug]: https://github.com/kelektiv/node.bcrypt.js/wiki/Security-Issues-and-Concerns#bcrypt-wrap-around-bug-medium-severity
|
||||||
|
[improper-nuls]: https://github.com/kelektiv/node.bcrypt.js/wiki/Security-Issues-and-Concerns#improper-nul-handling-medium-severity
|
||||||
|
|
||||||
|
[shadowfiend]:https://github.com/Shadowfiend
|
||||||
|
[thegoleffect]:https://github.com/thegoleffect
|
||||||
|
[pixelglow]:https://github.com/pixelglow
|
||||||
|
[dtrejo]:https://github.com/dtrejo
|
||||||
|
[alfredwesterveld]:https://github.com/alfredwesterveld
|
||||||
|
[newitfarmer]:https://github.com/newitfarmer
|
||||||
|
[zooko]:https://twitter.com/zooko
|
||||||
|
[vincentr]:https://twitter.com/vincentcr
|
||||||
|
[lloyd]:https://github.com/lloyd
|
||||||
|
[shtylman]:https://github.com/shtylman
|
||||||
|
[vadimg]:https://github.com/vadimg
|
||||||
|
[bnoordhuis]:https://github.com/bnoordhuis
|
||||||
|
[tootallnate]:https://github.com/tootallnate
|
||||||
|
[seanmonstar]:https://github.com/seanmonstar
|
||||||
|
[weareu]:https://github.com/weareu
|
||||||
|
[recrsn]:https://github.com/recrsn
|
||||||
|
[NickNaso]: https://github.com/NickNaso
|
||||||
15
node_modules/bcrypt/SECURITY.md
generated
vendored
Normal file
15
node_modules/bcrypt/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
As with any software, `bcrypt` is likely to have bugs. Please report any security vulnerabilities responsibly
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 5.0.x | :white_check_mark: |
|
||||||
|
| < 5.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you are reporting a security vulnerability, please refrain from opening a GitHub issue and instead mail it to
|
||||||
|
one of the maintainers listed in the README.
|
||||||
242
node_modules/bcrypt/bcrypt.js
generated
vendored
Normal file
242
node_modules/bcrypt/bcrypt.js
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const bindings = require('node-gyp-build')(path.resolve(__dirname));
|
||||||
|
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const promises = require('./promises');
|
||||||
|
|
||||||
|
/// generate a salt (sync)
|
||||||
|
/// @param {Number} [rounds] number of rounds (default 10)
|
||||||
|
/// @return {String} salt
|
||||||
|
function genSaltSync(rounds, minor) {
|
||||||
|
// default 10 rounds
|
||||||
|
if (!rounds) {
|
||||||
|
rounds = 10;
|
||||||
|
} else if (typeof rounds !== 'number') {
|
||||||
|
throw new Error('rounds must be a number');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!minor) {
|
||||||
|
minor = 'b';
|
||||||
|
} else if (minor !== 'b' && minor !== 'a') {
|
||||||
|
throw new Error('minor must be either "a" or "b"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.gen_salt_sync(minor, rounds, crypto.randomBytes(16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generate a salt
|
||||||
|
/// @param {Number} [rounds] number of rounds (default 10)
|
||||||
|
/// @param {Function} cb callback(err, salt)
|
||||||
|
function genSalt(rounds, minor, cb) {
|
||||||
|
let error;
|
||||||
|
|
||||||
|
// if callback is first argument, then use defaults for others
|
||||||
|
if (typeof arguments[0] === 'function') {
|
||||||
|
// have to set callback first otherwise arguments are overridden
|
||||||
|
cb = arguments[0];
|
||||||
|
rounds = 10;
|
||||||
|
minor = 'b';
|
||||||
|
// callback is second argument
|
||||||
|
} else if (typeof arguments[1] === 'function') {
|
||||||
|
// have to set callback first otherwise arguments are overridden
|
||||||
|
cb = arguments[1];
|
||||||
|
minor = 'b';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cb) {
|
||||||
|
return promises.promise(genSalt, this, [rounds, minor]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default 10 rounds
|
||||||
|
if (!rounds) {
|
||||||
|
rounds = 10;
|
||||||
|
} else if (typeof rounds !== 'number') {
|
||||||
|
// callback error asynchronously
|
||||||
|
error = new Error('rounds must be a number');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!minor) {
|
||||||
|
minor = 'b'
|
||||||
|
} else if (minor !== 'b' && minor !== 'a') {
|
||||||
|
error = new Error('minor must be either "a" or "b"');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto.randomBytes(16, function (error, randomBytes) {
|
||||||
|
if (error) {
|
||||||
|
cb(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings.gen_salt(minor, rounds, randomBytes, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// hash data using a salt
|
||||||
|
/// @param {String|Buffer} data the data to encrypt
|
||||||
|
/// @param {String} salt the salt to use when hashing
|
||||||
|
/// @return {String} hash
|
||||||
|
function hashSync(data, salt) {
|
||||||
|
if (data == null || salt == null) {
|
||||||
|
throw new Error('data and salt arguments required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) {
|
||||||
|
throw new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof salt === 'number') {
|
||||||
|
salt = module.exports.genSaltSync(salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.encrypt_sync(data, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// hash data using a salt
|
||||||
|
/// @param {String|Buffer} data the data to encrypt
|
||||||
|
/// @param {String} salt the salt to use when hashing
|
||||||
|
/// @param {Function} cb callback(err, hash)
|
||||||
|
function hash(data, salt, cb) {
|
||||||
|
let error;
|
||||||
|
|
||||||
|
if (typeof data === 'function') {
|
||||||
|
error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
data(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof salt === 'function') {
|
||||||
|
error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
salt(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// cb exists but is not a function
|
||||||
|
// return a rejecting promise
|
||||||
|
if (cb && typeof cb !== 'function') {
|
||||||
|
return promises.reject(new Error('cb must be a function or null to return a Promise'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cb) {
|
||||||
|
return promises.promise(hash, this, [data, salt]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == null || salt == null) {
|
||||||
|
error = new Error('data and salt arguments required');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(typeof data === 'string' || data instanceof Buffer) || (typeof salt !== 'string' && typeof salt !== 'number')) {
|
||||||
|
error = new Error('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof salt === 'number') {
|
||||||
|
return module.exports.genSalt(salt, function (err, salt) {
|
||||||
|
return bindings.encrypt(data, salt, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.encrypt(data, salt, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compare raw data to hash
|
||||||
|
/// @param {String|Buffer} data the data to hash and compare
|
||||||
|
/// @param {String} hash expected hash
|
||||||
|
/// @return {bool} true if hashed data matches hash
|
||||||
|
function compareSync(data, hash) {
|
||||||
|
if (data == null || hash == null) {
|
||||||
|
throw new Error('data and hash arguments required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') {
|
||||||
|
throw new Error('data must be a string or Buffer and hash must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.compare_sync(data, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compare raw data to hash
|
||||||
|
/// @param {String|Buffer} data the data to hash and compare
|
||||||
|
/// @param {String} hash expected hash
|
||||||
|
/// @param {Function} cb callback(err, matched) - matched is true if hashed data matches hash
|
||||||
|
function compare(data, hash, cb) {
|
||||||
|
let error;
|
||||||
|
|
||||||
|
if (typeof data === 'function') {
|
||||||
|
error = new Error('data and hash arguments required');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
data(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof hash === 'function') {
|
||||||
|
error = new Error('data and hash arguments required');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
hash(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// cb exists but is not a function
|
||||||
|
// return a rejecting promise
|
||||||
|
if (cb && typeof cb !== 'function') {
|
||||||
|
return promises.reject(new Error('cb must be a function or null to return a Promise'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cb) {
|
||||||
|
return promises.promise(compare, this, [data, hash]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == null || hash == null) {
|
||||||
|
error = new Error('data and hash arguments required');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(typeof data === 'string' || data instanceof Buffer) || typeof hash !== 'string') {
|
||||||
|
error = new Error('data and hash must be strings');
|
||||||
|
return process.nextTick(function () {
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.compare(data, hash, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param {String} hash extract rounds from this hash
|
||||||
|
/// @return {Number} the number of rounds used to encrypt a given hash
|
||||||
|
function getRounds(hash) {
|
||||||
|
if (hash == null) {
|
||||||
|
throw new Error('hash argument required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof hash !== 'string') {
|
||||||
|
throw new Error('hash must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings.get_rounds(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
genSaltSync,
|
||||||
|
genSalt,
|
||||||
|
hashSync,
|
||||||
|
hash,
|
||||||
|
compareSync,
|
||||||
|
compare,
|
||||||
|
getRounds,
|
||||||
|
}
|
||||||
49
node_modules/bcrypt/binding.gyp
generated
vendored
Normal file
49
node_modules/bcrypt/binding.gyp
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"variables": {
|
||||||
|
"NODE_VERSION%":"<!(node -p \"process.versions.node.split(\\\".\\\")[0]\")"
|
||||||
|
},
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'bcrypt_lib',
|
||||||
|
'sources': [
|
||||||
|
'src/blowfish.cc',
|
||||||
|
'src/bcrypt.cc',
|
||||||
|
'src/bcrypt_node.cc'
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'_GNU_SOURCE',
|
||||||
|
],
|
||||||
|
'cflags!': [ '-fno-exceptions' ],
|
||||||
|
'cflags_cc!': [ '-fno-exceptions' ],
|
||||||
|
'dependencies': [
|
||||||
|
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['OS=="win"', {
|
||||||
|
"msvs_settings": {
|
||||||
|
"VCCLCompilerTool": {
|
||||||
|
"ExceptionHandling": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'defines': [
|
||||||
|
'uint=unsigned int',
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'cflags+': ['-fvisibility=hidden'],
|
||||||
|
"xcode_settings": {
|
||||||
|
"CLANG_CXX_LIBRARY": "libc++",
|
||||||
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||||
|
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
['OS=="zos" and NODE_VERSION <= 16',{
|
||||||
|
'cflags': [
|
||||||
|
'-qascii',
|
||||||
|
],
|
||||||
|
'defines': ["NAPI_DISABLE_CPP_EXCEPTIONS"],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
37
node_modules/bcrypt/build-all.sh
generated
vendored
Normal file
37
node_modules/bcrypt/build-all.sh
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash -ue
|
||||||
|
|
||||||
|
CLEAN=${CLEAN:-""}
|
||||||
|
RUN_TESTS=${RUN_TESTS:-true}
|
||||||
|
|
||||||
|
if [ -n "$CLEAN" ]; then
|
||||||
|
rm -rf build build-tmp*
|
||||||
|
rm -rf lib/binding
|
||||||
|
rm -rf prebuilds
|
||||||
|
fi
|
||||||
|
|
||||||
|
npm i -g prebuildify@5 node-gyp@9
|
||||||
|
npm ci
|
||||||
|
#npm run build
|
||||||
|
|
||||||
|
for PLATFORM in linux/amd64 linux/arm64/v8 linux/arm/v7; do
|
||||||
|
echo -- build for $PLATFORM --
|
||||||
|
BUILDER_NAME="bcryptjs-${PLATFORM//\/-}-builder"
|
||||||
|
docker build -t "$BUILDER_NAME" \
|
||||||
|
--build-arg RUN_TESTS="$RUN_TESTS" \
|
||||||
|
--platform "$PLATFORM" .
|
||||||
|
CONTAINER=$(docker create --platform "$PLATFORM" "$BUILDER_NAME")
|
||||||
|
docker cp "$CONTAINER:/usr/local/opt/bcrypt-js/prebuilds" .
|
||||||
|
docker rm "$CONTAINER"
|
||||||
|
|
||||||
|
echo -- build for $PLATFORM Alpine --
|
||||||
|
BUILDER_NAME="bcryptjs-${PLATFORM//\/-}-alpine-builder"
|
||||||
|
docker build -t "$BUILDER_NAME" -f Dockerfile-alpine \
|
||||||
|
--build-arg RUN_TESTS="$RUN_TESTS" \
|
||||||
|
--platform "$PLATFORM" .
|
||||||
|
CONTAINER=$(docker create --platform "$PLATFORM" "$BUILDER_NAME")
|
||||||
|
docker cp "$CONTAINER:/usr/local/opt/bcrypt-js/prebuilds" .
|
||||||
|
docker rm "$CONTAINER"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
ls -lF prebuilds/
|
||||||
28
node_modules/bcrypt/examples/async_compare.js
generated
vendored
Normal file
28
node_modules/bcrypt/examples/async_compare.js
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
|
// genSalt
|
||||||
|
const salt = await bcrypt.genSalt(10)
|
||||||
|
console.log('salt: ' + salt);
|
||||||
|
console.log('salt cb end: ' + (Date.now() - start) + 'ms');
|
||||||
|
|
||||||
|
// hash
|
||||||
|
const crypted = await bcrypt.hash('test', salt)
|
||||||
|
console.log('crypted: ' + crypted);
|
||||||
|
console.log('crypted cb end: ' + (Date.now() - start) + 'ms');
|
||||||
|
console.log('rounds used from hash:', bcrypt.getRounds(crypted));
|
||||||
|
|
||||||
|
// compare
|
||||||
|
const res = await bcrypt.compare('test', crypted)
|
||||||
|
console.log('compared true: ' + res);
|
||||||
|
console.log('compared true cb end: ' + (Date.now() - start) + 'ms');
|
||||||
|
|
||||||
|
// compare
|
||||||
|
const res2 = await bcrypt.compare('bacon', crypted)
|
||||||
|
console.log('compared false: ' + res2);
|
||||||
|
console.log('compared false cb end: ' + (Date.now() - start) + 'ms');
|
||||||
|
|
||||||
|
console.log('end: ' + (Date.now() - start) + 'ms');
|
||||||
|
})();
|
||||||
8
node_modules/bcrypt/examples/forever_gen_salt.js
generated
vendored
Normal file
8
node_modules/bcrypt/examples/forever_gen_salt.js
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
|
||||||
|
(function printSalt() {
|
||||||
|
bcrypt.genSalt(10, (err, salt) => {
|
||||||
|
console.log('salt: ' + salt);
|
||||||
|
printSalt();
|
||||||
|
});
|
||||||
|
})()
|
||||||
9
node_modules/bcrypt/node_modules/node-addon-api/LICENSE.md
generated
vendored
Normal file
9
node_modules/bcrypt/node_modules/node-addon-api/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 [Node.js API collaborators](https://github.com/nodejs/node-addon-api#collaborators)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
95
node_modules/bcrypt/node_modules/node-addon-api/README.md
generated
vendored
Normal file
95
node_modules/bcrypt/node_modules/node-addon-api/README.md
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# **node-addon-api module**
|
||||||
|
|
||||||
|
[](https://app.codecov.io/gh/nodejs/node-addon-api/tree/main)
|
||||||
|
|
||||||
|
[](https://nodei.co/npm/node-addon-api/) [](https://nodei.co/npm/node-addon-api/)
|
||||||
|
|
||||||
|
This module contains **header-only C++ wrapper classes** which simplify
|
||||||
|
the use of the C based [Node-API](https://nodejs.org/dist/latest/docs/api/n-api.html)
|
||||||
|
provided by Node.js when using C++. It provides a C++ object model
|
||||||
|
and exception handling semantics with low overhead.
|
||||||
|
|
||||||
|
- [API References](doc/README.md)
|
||||||
|
- [Badges](#badges)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
## API References
|
||||||
|
|
||||||
|
API references are available in the [doc](doc/README.md) directory.
|
||||||
|
|
||||||
|
<!-- x-release-please-start-version -->
|
||||||
|
## Current version: 8.6.0
|
||||||
|
<!-- x-release-please-end -->
|
||||||
|
|
||||||
|
(See [CHANGELOG.md](CHANGELOG.md) for complete Changelog)
|
||||||
|
|
||||||
|
node-addon-api is based on [Node-API](https://nodejs.org/api/n-api.html) and supports using different Node-API versions.
|
||||||
|
This allows addons built with it to run with Node.js versions which support the targeted Node-API version.
|
||||||
|
**However** the node-addon-api support model is to support only the active LTS Node.js versions. This means that
|
||||||
|
every year there will be a new major which drops support for the Node.js LTS version which has gone out of service.
|
||||||
|
|
||||||
|
The oldest Node.js version supported by the current version of node-addon-api is Node.js 18.x.
|
||||||
|
|
||||||
|
## Badges
|
||||||
|
|
||||||
|
The use of badges is recommended to indicate the minimum version of Node-API
|
||||||
|
required for the module. This helps to determine which Node.js major versions are
|
||||||
|
supported. Addon maintainers can consult the [Node-API support matrix][] to determine
|
||||||
|
which Node.js versions provide a given Node-API version. The following badges are
|
||||||
|
available:
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We love contributions from the community to **node-addon-api**!
|
||||||
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for more details on our philosophy around extending this module.
|
||||||
|
|
||||||
|
## Team members
|
||||||
|
|
||||||
|
### Active
|
||||||
|
|
||||||
|
| Name | GitHub Link |
|
||||||
|
| ------------------- | ----------------------------------------------------- |
|
||||||
|
| Anna Henningsen | [addaleax](https://github.com/addaleax) |
|
||||||
|
| Chengzhong Wu | [legendecas](https://github.com/legendecas) |
|
||||||
|
| Jack Xia | [JckXia](https://github.com/JckXia) |
|
||||||
|
| Kevin Eady | [KevinEady](https://github.com/KevinEady) |
|
||||||
|
| Michael Dawson | [mhdawson](https://github.com/mhdawson) |
|
||||||
|
| Nicola Del Gobbo | [NickNaso](https://github.com/NickNaso) |
|
||||||
|
| Vladimir Morozov | [vmoroz](https://github.com/vmoroz) |
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary>Emeritus</summary>
|
||||||
|
|
||||||
|
### Emeritus
|
||||||
|
|
||||||
|
| Name | GitHub Link |
|
||||||
|
| ------------------- | ----------------------------------------------------- |
|
||||||
|
| Arunesh Chandra | [aruneshchandra](https://github.com/aruneshchandra) |
|
||||||
|
| Benjamin Byholm | [kkoopa](https://github.com/kkoopa) |
|
||||||
|
| Gabriel Schulhof | [gabrielschulhof](https://github.com/gabrielschulhof) |
|
||||||
|
| Hitesh Kanwathirtha | [digitalinfinity](https://github.com/digitalinfinity) |
|
||||||
|
| Jason Ginchereau | [jasongin](https://github.com/jasongin) |
|
||||||
|
| Jim Schlight | [jschlight](https://github.com/jschlight) |
|
||||||
|
| Sampson Gao | [sampsongao](https://github.com/sampsongao) |
|
||||||
|
| Taylor Woll | [boingoing](https://github.com/boingoing) |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under [MIT](./LICENSE.md)
|
||||||
|
|
||||||
|
[Node-API support matrix]: https://nodejs.org/dist/latest/docs/api/n-api.html#node-api-version-matrix
|
||||||
21
node_modules/bcrypt/node_modules/node-addon-api/common.gypi
generated
vendored
Normal file
21
node_modules/bcrypt/node_modules/node-addon-api/common.gypi
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
'NAPI_VERSION%': "<!(node -p \"process.env.NAPI_VERSION || process.versions.napi\")",
|
||||||
|
'disable_deprecated': "<!(node -p \"process.env['npm_config_disable_deprecated']\")"
|
||||||
|
},
|
||||||
|
'conditions': [
|
||||||
|
['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
|
||||||
|
['NAPI_VERSION==2147483647', { 'defines': ['NAPI_EXPERIMENTAL', 'NODE_API_EXPERIMENTAL_NO_WARNING'] } ],
|
||||||
|
['disable_deprecated=="true"', {
|
||||||
|
'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
|
||||||
|
}],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'cflags+': ['-fvisibility=hidden'],
|
||||||
|
'xcode_settings': {
|
||||||
|
'OTHER_CFLAGS': ['-fvisibility=hidden']
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
'cflags': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ],
|
||||||
|
'cflags_cc': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ]
|
||||||
|
}
|
||||||
25
node_modules/bcrypt/node_modules/node-addon-api/except.gypi
generated
vendored
Normal file
25
node_modules/bcrypt/node_modules/node-addon-api/except.gypi
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
'defines': [ 'NAPI_CPP_EXCEPTIONS' ],
|
||||||
|
'cflags!': [ '-fno-exceptions' ],
|
||||||
|
'cflags_cc!': [ '-fno-exceptions' ],
|
||||||
|
'conditions': [
|
||||||
|
["OS=='win'", {
|
||||||
|
"defines": [
|
||||||
|
"_HAS_EXCEPTIONS=1"
|
||||||
|
],
|
||||||
|
"msvs_settings": {
|
||||||
|
"VCCLCompilerTool": {
|
||||||
|
"ExceptionHandling": 1,
|
||||||
|
'EnablePREfast': 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
["OS=='mac'", {
|
||||||
|
'xcode_settings': {
|
||||||
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||||
|
'CLANG_CXX_LIBRARY': 'libc++',
|
||||||
|
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
}
|
||||||
14
node_modules/bcrypt/node_modules/node-addon-api/index.js
generated
vendored
Normal file
14
node_modules/bcrypt/node_modules/node-addon-api/index.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { version } = require('./package.json');
|
||||||
|
|
||||||
|
const includeDir = path.relative('.', __dirname);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
include: `"${__dirname}"`, // deprecated, can be removed as part of 4.0.0
|
||||||
|
include_dir: includeDir,
|
||||||
|
gyp: path.join(includeDir, 'node_api.gyp:nothing'), // deprecated.
|
||||||
|
targets: path.join(includeDir, 'node_addon_api.gyp'),
|
||||||
|
version,
|
||||||
|
isNodeApiBuiltin: true,
|
||||||
|
needsFlag: false
|
||||||
|
};
|
||||||
186
node_modules/bcrypt/node_modules/node-addon-api/napi-inl.deprecated.h
generated
vendored
Normal file
186
node_modules/bcrypt/node_modules/node-addon-api/napi-inl.deprecated.h
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#ifndef SRC_NAPI_INL_DEPRECATED_H_
|
||||||
|
#define SRC_NAPI_INL_DEPRECATED_H_
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PropertyDescriptor class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <typename Getter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
const char* utf8name,
|
||||||
|
Getter getter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using CbData = details::CallbackData<Getter, Napi::Value>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({getter, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({utf8name,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
CbData::Wrapper,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
const std::string& utf8name,
|
||||||
|
Getter getter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* data) {
|
||||||
|
return Accessor(utf8name.c_str(), getter, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
napi_value name,
|
||||||
|
Getter getter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using CbData = details::CallbackData<Getter, Napi::Value>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({getter, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({nullptr,
|
||||||
|
name,
|
||||||
|
nullptr,
|
||||||
|
CbData::Wrapper,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
Name name, Getter getter, napi_property_attributes attributes, void* data) {
|
||||||
|
napi_value nameValue = name;
|
||||||
|
return PropertyDescriptor::Accessor(nameValue, getter, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter, typename Setter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
const char* utf8name,
|
||||||
|
Getter getter,
|
||||||
|
Setter setter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using CbData = details::AccessorCallbackData<Getter, Setter>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({getter, setter, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({utf8name,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
CbData::GetterWrapper,
|
||||||
|
CbData::SetterWrapper,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter, typename Setter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
const std::string& utf8name,
|
||||||
|
Getter getter,
|
||||||
|
Setter setter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* data) {
|
||||||
|
return Accessor(utf8name.c_str(), getter, setter, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter, typename Setter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
napi_value name,
|
||||||
|
Getter getter,
|
||||||
|
Setter setter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using CbData = details::AccessorCallbackData<Getter, Setter>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({getter, setter, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({nullptr,
|
||||||
|
name,
|
||||||
|
nullptr,
|
||||||
|
CbData::GetterWrapper,
|
||||||
|
CbData::SetterWrapper,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter, typename Setter>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||||
|
Name name,
|
||||||
|
Getter getter,
|
||||||
|
Setter setter,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* data) {
|
||||||
|
napi_value nameValue = name;
|
||||||
|
return PropertyDescriptor::Accessor(
|
||||||
|
nameValue, getter, setter, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||||
|
const char* utf8name,
|
||||||
|
Callable cb,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr)));
|
||||||
|
using CbData = details::CallbackData<Callable, ReturnType>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({cb, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({utf8name,
|
||||||
|
nullptr,
|
||||||
|
CbData::Wrapper,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||||
|
const std::string& utf8name,
|
||||||
|
Callable cb,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* data) {
|
||||||
|
return Function(utf8name.c_str(), cb, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||||
|
napi_value name,
|
||||||
|
Callable cb,
|
||||||
|
napi_property_attributes attributes,
|
||||||
|
void* /*data*/) {
|
||||||
|
using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr)));
|
||||||
|
using CbData = details::CallbackData<Callable, ReturnType>;
|
||||||
|
// TODO: Delete when the function is destroyed
|
||||||
|
auto callbackData = new CbData({cb, nullptr});
|
||||||
|
|
||||||
|
return PropertyDescriptor({nullptr,
|
||||||
|
name,
|
||||||
|
CbData::Wrapper,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
attributes,
|
||||||
|
callbackData});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||||
|
Name name, Callable cb, napi_property_attributes attributes, void* data) {
|
||||||
|
napi_value nameValue = name;
|
||||||
|
return PropertyDescriptor::Function(nameValue, cb, attributes, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !SRC_NAPI_INL_DEPRECATED_H_
|
||||||
7108
node_modules/bcrypt/node_modules/node-addon-api/napi-inl.h
generated
vendored
Normal file
7108
node_modules/bcrypt/node_modules/node-addon-api/napi-inl.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3327
node_modules/bcrypt/node_modules/node-addon-api/napi.h
generated
vendored
Normal file
3327
node_modules/bcrypt/node_modules/node-addon-api/napi.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
42
node_modules/bcrypt/node_modules/node-addon-api/node_addon_api.gyp
generated
vendored
Normal file
42
node_modules/bcrypt/node_modules/node-addon-api/node_addon_api.gyp
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'node_addon_api',
|
||||||
|
'type': 'none',
|
||||||
|
'sources': [ 'napi.h', 'napi-inl.h' ],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [ '.' ],
|
||||||
|
'includes': ['noexcept.gypi'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'node_addon_api_except',
|
||||||
|
'type': 'none',
|
||||||
|
'sources': [ 'napi.h', 'napi-inl.h' ],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [ '.' ],
|
||||||
|
'includes': ['except.gypi'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'node_addon_api_except_all',
|
||||||
|
'type': 'none',
|
||||||
|
'sources': [ 'napi.h', 'napi-inl.h' ],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [ '.' ],
|
||||||
|
'includes': ['except.gypi'],
|
||||||
|
'defines': [ 'NODE_ADDON_API_CPP_EXCEPTIONS_ALL' ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'node_addon_api_maybe',
|
||||||
|
'type': 'none',
|
||||||
|
'sources': [ 'napi.h', 'napi-inl.h' ],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [ '.' ],
|
||||||
|
'includes': ['noexcept.gypi'],
|
||||||
|
'defines': ['NODE_ADDON_API_ENABLE_MAYBE']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
9
node_modules/bcrypt/node_modules/node-addon-api/node_api.gyp
generated
vendored
Normal file
9
node_modules/bcrypt/node_modules/node-addon-api/node_api.gyp
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'nothing',
|
||||||
|
'type': 'static_library',
|
||||||
|
'sources': [ 'nothing.c' ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
node_modules/bcrypt/node_modules/node-addon-api/noexcept.gypi
generated
vendored
Normal file
26
node_modules/bcrypt/node_modules/node-addon-api/noexcept.gypi
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
'defines': [ 'NODE_ADDON_API_DISABLE_CPP_EXCEPTIONS' ],
|
||||||
|
'cflags': [ '-fno-exceptions' ],
|
||||||
|
'cflags_cc': [ '-fno-exceptions' ],
|
||||||
|
'conditions': [
|
||||||
|
["OS=='win'", {
|
||||||
|
# _HAS_EXCEPTIONS is already defined and set to 0 in common.gypi
|
||||||
|
#"defines": [
|
||||||
|
# "_HAS_EXCEPTIONS=0"
|
||||||
|
#],
|
||||||
|
"msvs_settings": {
|
||||||
|
"VCCLCompilerTool": {
|
||||||
|
'ExceptionHandling': 0,
|
||||||
|
'EnablePREfast': 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
["OS=='mac'", {
|
||||||
|
'xcode_settings': {
|
||||||
|
'CLANG_CXX_LIBRARY': 'libc++',
|
||||||
|
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
||||||
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
}
|
||||||
0
node_modules/bcrypt/node_modules/node-addon-api/nothing.c
generated
vendored
Normal file
0
node_modules/bcrypt/node_modules/node-addon-api/nothing.c
generated
vendored
Normal file
21
node_modules/bcrypt/node_modules/node-addon-api/package-support.json
generated
vendored
Normal file
21
node_modules/bcrypt/node_modules/node-addon-api/package-support.json
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "*",
|
||||||
|
"target": {
|
||||||
|
"node": "active"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"type": "time-permitting",
|
||||||
|
"paid": false,
|
||||||
|
"contact": {
|
||||||
|
"name": "node-addon-api team",
|
||||||
|
"url": "https://github.com/nodejs/node-addon-api/issues"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"backing": [ { "project": "https://github.com/nodejs" },
|
||||||
|
{ "foundation": "https://openjsf.org/" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
480
node_modules/bcrypt/node_modules/node-addon-api/package.json
generated
vendored
Normal file
480
node_modules/bcrypt/node_modules/node-addon-api/package.json
generated
vendored
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
{
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/nodejs/node-addon-api/issues"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Abhishek Kumar Singh",
|
||||||
|
"url": "https://github.com/abhi11210646"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alba Mendez",
|
||||||
|
"url": "https://github.com/jmendeth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alexander Floh",
|
||||||
|
"url": "https://github.com/alexanderfloh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ammar Faizi",
|
||||||
|
"url": "https://github.com/ammarfaizi2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "András Timár, Dr",
|
||||||
|
"url": "https://github.com/timarandras"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Andrew Petersen",
|
||||||
|
"url": "https://github.com/kirbysayshi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Anisha Rohra",
|
||||||
|
"url": "https://github.com/anisha-rohra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Anna Henningsen",
|
||||||
|
"url": "https://github.com/addaleax"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arnaud Botella",
|
||||||
|
"url": "https://github.com/BotellaA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arunesh Chandra",
|
||||||
|
"url": "https://github.com/aruneshchandra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Azlan Mukhtar",
|
||||||
|
"url": "https://github.com/azlan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ben Berman",
|
||||||
|
"url": "https://github.com/rivertam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Byholm",
|
||||||
|
"url": "https://github.com/kkoopa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bill Gallafent",
|
||||||
|
"url": "https://github.com/gallafent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "blagoev",
|
||||||
|
"url": "https://github.com/blagoev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bruce A. MacNaughton",
|
||||||
|
"url": "https://github.com/bmacnaughton"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cory Mickelson",
|
||||||
|
"url": "https://github.com/corymickelson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Daniel Bevenius",
|
||||||
|
"url": "https://github.com/danbev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dante Calderón",
|
||||||
|
"url": "https://github.com/dantehemerson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Darshan Sen",
|
||||||
|
"url": "https://github.com/RaisinTen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David Halls",
|
||||||
|
"url": "https://github.com/davedoesdev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deepak Rajamohan",
|
||||||
|
"url": "https://github.com/deepakrkris"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dmitry Ashkadov",
|
||||||
|
"url": "https://github.com/dmitryash"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dongjin Na",
|
||||||
|
"url": "https://github.com/nadongguri"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Doni Rubiagatra",
|
||||||
|
"url": "https://github.com/rubiagatra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Eric Bickle",
|
||||||
|
"url": "https://github.com/ebickle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "extremeheat",
|
||||||
|
"url": "https://github.com/extremeheat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Feng Yu",
|
||||||
|
"url": "https://github.com/F3n67u"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ferdinand Holzer",
|
||||||
|
"url": "https://github.com/fholzer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gabriel Schulhof",
|
||||||
|
"url": "https://github.com/gabrielschulhof"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guenter Sandner",
|
||||||
|
"url": "https://github.com/gms1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gus Caplan",
|
||||||
|
"url": "https://github.com/devsnek"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Helio Frota",
|
||||||
|
"url": "https://github.com/helio-frota"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hitesh Kanwathirtha",
|
||||||
|
"url": "https://github.com/digitalinfinity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ikokostya",
|
||||||
|
"url": "https://github.com/ikokostya"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jack Xia",
|
||||||
|
"url": "https://github.com/JckXia"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jake Barnes",
|
||||||
|
"url": "https://github.com/DuBistKomisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jake Yoon",
|
||||||
|
"url": "https://github.com/yjaeseok"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jason Ginchereau",
|
||||||
|
"url": "https://github.com/jasongin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jenny",
|
||||||
|
"url": "https://github.com/egg-bread"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jeroen Janssen",
|
||||||
|
"url": "https://github.com/japj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jim Schlight",
|
||||||
|
"url": "https://github.com/jschlight"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jinho Bang",
|
||||||
|
"url": "https://github.com/romandev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "José Expósito",
|
||||||
|
"url": "https://github.com/JoseExposito"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "joshgarde",
|
||||||
|
"url": "https://github.com/joshgarde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Julian Mesa",
|
||||||
|
"url": "https://github.com/julianmesa-gitkraken"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kasumi Hanazuki",
|
||||||
|
"url": "https://github.com/hanazuki"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kelvin",
|
||||||
|
"url": "https://github.com/kelvinhammond"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kevin Eady",
|
||||||
|
"url": "https://github.com/KevinEady"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kévin VOYER",
|
||||||
|
"url": "https://github.com/kecsou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kidneysolo",
|
||||||
|
"url": "https://github.com/kidneysolo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Koki Nishihara",
|
||||||
|
"url": "https://github.com/Nishikoh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Konstantin Tarkus",
|
||||||
|
"url": "https://github.com/koistya"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kyle Farnung",
|
||||||
|
"url": "https://github.com/kfarnung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kyle Kovacs",
|
||||||
|
"url": "https://github.com/nullromo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "legendecas",
|
||||||
|
"url": "https://github.com/legendecas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LongYinan",
|
||||||
|
"url": "https://github.com/Brooooooklyn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lovell Fuller",
|
||||||
|
"url": "https://github.com/lovell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Luciano Martorella",
|
||||||
|
"url": "https://github.com/lmartorella"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mastergberry",
|
||||||
|
"url": "https://github.com/mastergberry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mathias Küsel",
|
||||||
|
"url": "https://github.com/mathiask88"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mathias Stearn",
|
||||||
|
"url": "https://github.com/RedBeard0531"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Matteo Collina",
|
||||||
|
"url": "https://github.com/mcollina"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Dawson",
|
||||||
|
"url": "https://github.com/mhdawson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Price",
|
||||||
|
"url": "https://github.com/mikepricedev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michele Campus",
|
||||||
|
"url": "https://github.com/kYroL01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mikhail Cheshkov",
|
||||||
|
"url": "https://github.com/mcheshkov"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nempoBu4",
|
||||||
|
"url": "https://github.com/nempoBu4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicola Del Gobbo",
|
||||||
|
"url": "https://github.com/NickNaso"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nick Soggin",
|
||||||
|
"url": "https://github.com/iSkore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nikolai Vavilov",
|
||||||
|
"url": "https://github.com/seishun"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nurbol Alpysbayev",
|
||||||
|
"url": "https://github.com/anurbol"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pacop",
|
||||||
|
"url": "https://github.com/pacop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Peter Šándor",
|
||||||
|
"url": "https://github.com/petersandor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Philipp Renoth",
|
||||||
|
"url": "https://github.com/DaAitch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rgerd",
|
||||||
|
"url": "https://github.com/rgerd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Richard Lau",
|
||||||
|
"url": "https://github.com/richardlau"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rolf Timmermans",
|
||||||
|
"url": "https://github.com/rolftimmermans"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ross Weir",
|
||||||
|
"url": "https://github.com/ross-weir"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ryuichi Okumura",
|
||||||
|
"url": "https://github.com/okuryu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Saint Gabriel",
|
||||||
|
"url": "https://github.com/chineduG"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sampson Gao",
|
||||||
|
"url": "https://github.com/sampsongao"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sam Roberts",
|
||||||
|
"url": "https://github.com/sam-github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "strager",
|
||||||
|
"url": "https://github.com/strager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Taylor Woll",
|
||||||
|
"url": "https://github.com/boingoing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Thomas Gentilhomme",
|
||||||
|
"url": "https://github.com/fraxken"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tim Rach",
|
||||||
|
"url": "https://github.com/timrach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tobias Nießen",
|
||||||
|
"url": "https://github.com/tniessen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "todoroff",
|
||||||
|
"url": "https://github.com/todoroff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Toyo Li",
|
||||||
|
"url": "https://github.com/toyobayashi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tux3",
|
||||||
|
"url": "https://github.com/tux3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vlad Velmisov",
|
||||||
|
"url": "https://github.com/Velmisov"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vladimir Morozov",
|
||||||
|
"url": "https://github.com/vmoroz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WenheLI",
|
||||||
|
"url": "https://github.com/WenheLI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Xuguang Mei",
|
||||||
|
"url": "https://github.com/meixg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Yohei Kishimoto",
|
||||||
|
"url": "https://github.com/morokosi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Yulong Wang",
|
||||||
|
"url": "https://github.com/fs-eire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ziqiu Zhao",
|
||||||
|
"url": "https://github.com/ZzqiZQute"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Feng Yu",
|
||||||
|
"url": "https://github.com/F3n67u"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wanlu wang",
|
||||||
|
"url": "https://github.com/wanlu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Caleb Hearon",
|
||||||
|
"url": "https://github.com/chearon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marx",
|
||||||
|
"url": "https://github.com/MarxJiao"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ömer AKGÜL",
|
||||||
|
"url": "https://github.com/tuhalf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Node.js API (Node-API)",
|
||||||
|
"devDependencies": {
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"clang-format": "^1.4.0",
|
||||||
|
"eslint": "^9.13.0",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
|
"neostandard": "^0.12.0",
|
||||||
|
"pre-commit": "^1.2.2",
|
||||||
|
"semver": "^7.6.0"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"gypfile": false,
|
||||||
|
"homepage": "https://github.com/nodejs/node-addon-api",
|
||||||
|
"keywords": [
|
||||||
|
"n-api",
|
||||||
|
"napi",
|
||||||
|
"addon",
|
||||||
|
"native",
|
||||||
|
"bindings",
|
||||||
|
"c",
|
||||||
|
"c++",
|
||||||
|
"nan",
|
||||||
|
"node-addon-api"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.js",
|
||||||
|
"name": "node-addon-api",
|
||||||
|
"readme": "README.md",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/nodejs/node-addon-api.git"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"*.{c,h,gyp,gypi}",
|
||||||
|
"package-support.json",
|
||||||
|
"tools/"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"prebenchmark": "node-gyp rebuild -C benchmark",
|
||||||
|
"benchmark": "node benchmark",
|
||||||
|
"create-coverage": "npm test --coverage",
|
||||||
|
"report-coverage-html": "rm -rf coverage-html && mkdir coverage-html && gcovr -e test --merge-mode-functions merge-use-line-max --html-nested ./coverage-html/index.html test",
|
||||||
|
"report-coverage-xml": "rm -rf coverage-xml && mkdir coverage-xml && gcovr -e test --merge-mode-functions merge-use-line-max --xml -o ./coverage-xml/coverage-cxx.xml test",
|
||||||
|
"pretest": "node-gyp rebuild -C test",
|
||||||
|
"test": "node test",
|
||||||
|
"test:debug": "node-gyp rebuild -C test --debug && NODE_API_BUILD_CONFIG=Debug node ./test/index.js",
|
||||||
|
"predev": "node-gyp rebuild -C test --debug",
|
||||||
|
"dev": "node test",
|
||||||
|
"predev:incremental": "node-gyp configure build -C test --debug",
|
||||||
|
"dev:incremental": "node test",
|
||||||
|
"doc": "doxygen doc/Doxyfile",
|
||||||
|
"lint": "eslint && node tools/clang-format",
|
||||||
|
"lint:fix": "eslint --fix && node tools/clang-format --fix"
|
||||||
|
},
|
||||||
|
"pre-commit": "lint",
|
||||||
|
"version": "8.6.0",
|
||||||
|
"support": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || ^20 || >= 21"
|
||||||
|
}
|
||||||
|
}
|
||||||
73
node_modules/bcrypt/node_modules/node-addon-api/tools/README.md
generated
vendored
Normal file
73
node_modules/bcrypt/node_modules/node-addon-api/tools/README.md
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Tools
|
||||||
|
|
||||||
|
## clang-format
|
||||||
|
|
||||||
|
The clang-format checking tools is designed to check changed lines of code compared to given git-refs.
|
||||||
|
|
||||||
|
## Migration Script
|
||||||
|
|
||||||
|
The migration tool is designed to reduce repetitive work in the migration process. However, the script is not aiming to convert every thing for you. There are usually some small fixes and major reconstruction required.
|
||||||
|
|
||||||
|
### How To Use
|
||||||
|
|
||||||
|
To run the conversion script, first make sure you have the latest `node-addon-api` in your `node_modules` directory.
|
||||||
|
```
|
||||||
|
npm install node-addon-api
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run the script passing your project directory
|
||||||
|
```
|
||||||
|
node ./node_modules/node-addon-api/tools/conversion.js ./
|
||||||
|
```
|
||||||
|
|
||||||
|
After finish, recompile and debug things that are missed by the script.
|
||||||
|
|
||||||
|
|
||||||
|
### Quick Fixes
|
||||||
|
Here is the list of things that can be fixed easily.
|
||||||
|
1. Change your methods' return value to void if it doesn't return value to JavaScript.
|
||||||
|
2. Use `.` to access attribute or to invoke member function in Napi::Object instead of `->`.
|
||||||
|
3. `Napi::New(env, value);` to `Napi::[Type]::New(env, value);
|
||||||
|
|
||||||
|
|
||||||
|
### Major Reconstructions
|
||||||
|
The implementation of `Napi::ObjectWrap` is significantly different from NAN's. `Napi::ObjectWrap` takes a pointer to the wrapped object and creates a reference to the wrapped object inside ObjectWrap constructor. `Napi::ObjectWrap` also associates wrapped object's instance methods to Javascript module instead of static methods like NAN.
|
||||||
|
|
||||||
|
So if you use Nan::ObjectWrap in your module, you will need to execute the following steps.
|
||||||
|
|
||||||
|
1. Convert your [ClassName]::New function to a constructor function that takes a `Napi::CallbackInfo`. Declare it as
|
||||||
|
```
|
||||||
|
[ClassName](const Napi::CallbackInfo& info);
|
||||||
|
```
|
||||||
|
and define it as
|
||||||
|
```
|
||||||
|
[ClassName]::[ClassName](const Napi::CallbackInfo& info) : Napi::ObjectWrap<[ClassName]>(info){
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This way, the `Napi::ObjectWrap` constructor will be invoked after the object has been instantiated and `Napi::ObjectWrap` can use the `this` pointer to create a reference to the wrapped object.
|
||||||
|
|
||||||
|
2. Move your original constructor code into the new constructor. Delete your original constructor.
|
||||||
|
3. In your class initialization function, associate native methods in the following way.
|
||||||
|
```
|
||||||
|
Napi::FunctionReference constructor;
|
||||||
|
|
||||||
|
void [ClassName]::Init(Napi::Env env, Napi::Object exports, Napi::Object module) {
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Napi::Function ctor = DefineClass(env, "Canvas", {
|
||||||
|
InstanceMethod<&[ClassName]::Func1>("Func1"),
|
||||||
|
InstanceMethod<&[ClassName]::Func2>("Func2"),
|
||||||
|
InstanceAccessor<&[ClassName]::ValueGetter>("Value"),
|
||||||
|
StaticMethod<&[ClassName]::StaticMethod>("MethodName"),
|
||||||
|
InstanceValue("Value", Napi::[Type]::New(env, value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor = Napi::Persistent(ctor);
|
||||||
|
constructor .SuppressDestruct();
|
||||||
|
exports.Set("[ClassName]", ctor);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
4. In function where you need to Unwrap the ObjectWrap in NAN like `[ClassName]* native = Nan::ObjectWrap::Unwrap<[ClassName]>(info.This());`, use `this` pointer directly as the unwrapped object as each ObjectWrap instance is associated with a unique object instance.
|
||||||
|
|
||||||
|
|
||||||
|
If you still find issues after following this guide, please leave us an issue describing your problem and we will try to resolve it.
|
||||||
99
node_modules/bcrypt/node_modules/node-addon-api/tools/check-napi.js
generated
vendored
Normal file
99
node_modules/bcrypt/node_modules/node-addon-api/tools/check-napi.js
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
'use strict';
|
||||||
|
// Descend into a directory structure and, for each file matching *.node, output
|
||||||
|
// based on the imports found in the file whether it's an N-API module or not.
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// Read the output of the command, break it into lines, and use the reducer to
|
||||||
|
// decide whether the file is an N-API module or not.
|
||||||
|
function checkFile (file, command, argv, reducer) {
|
||||||
|
const child = require('child_process').spawn(command, argv, {
|
||||||
|
stdio: ['inherit', 'pipe', 'inherit']
|
||||||
|
});
|
||||||
|
let leftover = '';
|
||||||
|
let isNapi;
|
||||||
|
child.stdout.on('data', (chunk) => {
|
||||||
|
if (isNapi === undefined) {
|
||||||
|
chunk = (leftover + chunk.toString()).split(/[\r\n]+/);
|
||||||
|
leftover = chunk.pop();
|
||||||
|
isNapi = chunk.reduce(reducer, isNapi);
|
||||||
|
if (isNapi !== undefined) {
|
||||||
|
child.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
child.on('close', (code, signal) => {
|
||||||
|
if ((code === null && signal !== null) || (code !== 0)) {
|
||||||
|
console.log(
|
||||||
|
command + ' exited with code: ' + code + ' and signal: ' + signal);
|
||||||
|
} else {
|
||||||
|
// Green if it's a N-API module, red otherwise.
|
||||||
|
console.log(
|
||||||
|
'\x1b[' + (isNapi ? '42' : '41') + 'm' +
|
||||||
|
(isNapi ? ' N-API' : 'Not N-API') +
|
||||||
|
'\x1b[0m: ' + file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use nm -a to list symbols.
|
||||||
|
function checkFileUNIX (file) {
|
||||||
|
checkFile(file, 'nm', ['-a', file], (soFar, line) => {
|
||||||
|
if (soFar === undefined) {
|
||||||
|
line = line.match(/([0-9a-f]*)? ([a-zA-Z]) (.*$)/);
|
||||||
|
if (line[2] === 'U') {
|
||||||
|
if (/^napi/.test(line[3])) {
|
||||||
|
soFar = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return soFar;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use dumpbin /imports to list symbols.
|
||||||
|
function checkFileWin32 (file) {
|
||||||
|
checkFile(file, 'dumpbin', ['/imports', file], (soFar, line) => {
|
||||||
|
if (soFar === undefined) {
|
||||||
|
line = line.match(/([0-9a-f]*)? +([a-zA-Z0-9]) (.*$)/);
|
||||||
|
if (line && /^napi/.test(line[line.length - 1])) {
|
||||||
|
soFar = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return soFar;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Descend into a directory structure and pass each file ending in '.node' to
|
||||||
|
// one of the above checks, depending on the OS.
|
||||||
|
function recurse (top) {
|
||||||
|
fs.readdir(top, (error, items) => {
|
||||||
|
if (error) {
|
||||||
|
throw new Error('error reading directory ' + top + ': ' + error);
|
||||||
|
}
|
||||||
|
items.forEach((item) => {
|
||||||
|
item = path.join(top, item);
|
||||||
|
fs.stat(item, ((item) => (error, stats) => {
|
||||||
|
if (error) {
|
||||||
|
throw new Error('error about ' + item + ': ' + error);
|
||||||
|
}
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
recurse(item);
|
||||||
|
} else if (/[.]node$/.test(item) &&
|
||||||
|
// Explicitly ignore files called 'nothing.node' because they are
|
||||||
|
// artefacts of node-addon-api having identified a version of
|
||||||
|
// Node.js that ships with a correct implementation of N-API.
|
||||||
|
path.basename(item) !== 'nothing.node') {
|
||||||
|
process.platform === 'win32'
|
||||||
|
? checkFileWin32(item)
|
||||||
|
: checkFileUNIX(item);
|
||||||
|
}
|
||||||
|
})(item));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the directory given on the command line or the current directory
|
||||||
|
// if nothing was given.
|
||||||
|
recurse(process.argv.length > 3 ? process.argv[2] : '.');
|
||||||
71
node_modules/bcrypt/node_modules/node-addon-api/tools/clang-format.js
generated
vendored
Normal file
71
node_modules/bcrypt/node_modules/node-addon-api/tools/clang-format.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const spawn = require('child_process').spawnSync;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const filesToCheck = ['*.h', '*.cc'];
|
||||||
|
const FORMAT_START = process.env.FORMAT_START || 'main';
|
||||||
|
|
||||||
|
function main (args) {
|
||||||
|
let fix = false;
|
||||||
|
while (args.length > 0) {
|
||||||
|
switch (args[0]) {
|
||||||
|
case '-f':
|
||||||
|
case '--fix':
|
||||||
|
fix = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
args.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
const clangFormatPath = path.dirname(require.resolve('clang-format'));
|
||||||
|
const binary = process.platform === 'win32'
|
||||||
|
? 'node_modules\\.bin\\clang-format.cmd'
|
||||||
|
: 'node_modules/.bin/clang-format';
|
||||||
|
const options = ['--binary=' + binary, '--style=file'];
|
||||||
|
if (fix) {
|
||||||
|
options.push(FORMAT_START);
|
||||||
|
} else {
|
||||||
|
options.push('--diff', FORMAT_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gitClangFormatPath = path.join(clangFormatPath, 'bin/git-clang-format');
|
||||||
|
const result = spawn(
|
||||||
|
'python',
|
||||||
|
[gitClangFormatPath, ...options, '--', ...filesToCheck],
|
||||||
|
{ encoding: 'utf-8' }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.stderr) {
|
||||||
|
console.error('Error running git-clang-format:', result.stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clangFormatOutput = result.stdout.trim();
|
||||||
|
// Bail fast if in fix mode.
|
||||||
|
if (fix) {
|
||||||
|
console.log(clangFormatOutput);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Detect if there is any complains from clang-format
|
||||||
|
if (
|
||||||
|
clangFormatOutput !== '' &&
|
||||||
|
clangFormatOutput !== 'no modified files to format' &&
|
||||||
|
clangFormatOutput !== 'clang-format did not modify any files'
|
||||||
|
) {
|
||||||
|
console.error(clangFormatOutput);
|
||||||
|
const fixCmd = 'npm run lint:fix';
|
||||||
|
console.error(`
|
||||||
|
ERROR: please run "${fixCmd}" to format changes in your commit
|
||||||
|
Note that when running the command locally, please keep your local
|
||||||
|
main branch and working branch up to date with nodejs/node-addon-api
|
||||||
|
to exclude un-related complains.
|
||||||
|
Or you can run "env FORMAT_START=upstream/main ${fixCmd}".`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
process.exitCode = main(process.argv.slice(2));
|
||||||
|
}
|
||||||
301
node_modules/bcrypt/node_modules/node-addon-api/tools/conversion.js
generated
vendored
Normal file
301
node_modules/bcrypt/node_modules/node-addon-api/tools/conversion.js
generated
vendored
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const dir = args[0];
|
||||||
|
if (!dir) {
|
||||||
|
console.log('Usage: node ' + path.basename(__filename) + ' <target-dir>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NodeApiVersion = require('../').version;
|
||||||
|
|
||||||
|
const disable = args[1];
|
||||||
|
let ConfigFileOperations;
|
||||||
|
if (disable !== '--disable' && dir !== '--disable') {
|
||||||
|
ConfigFileOperations = {
|
||||||
|
'package.json': [
|
||||||
|
[/([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'],
|
||||||
|
[/[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '']
|
||||||
|
],
|
||||||
|
'binding.gyp': [
|
||||||
|
[/([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'<!(node -p "require(\\\'node-addon-api\\\').include_dir")\','],
|
||||||
|
[/([ ]*)"include_dirs": \[/g, '$1"include_dirs": [\n$1 "<!(node -p \\"require(\'node-addon-api\').include_dir\\")",'],
|
||||||
|
[/[ ]*("|')<!\(node -e ("|'|\\"|\\')require\(("|'|\\"|\\')nan("|'|\\"|\\')\)("|'|\\"|\\')\)("|')(,|)[\r\n]/g, ''],
|
||||||
|
[/([ ]*)("|')target_name("|'): ("|')(.+?)("|'),/g, '$1$2target_name$2: $4$5$6,\n $2cflags!$2: [ $2-fno-exceptions$2 ],\n $2cflags_cc!$2: [ $2-fno-exceptions$2 ],\n $2xcode_settings$2: { $2GCC_ENABLE_CPP_EXCEPTIONS$2: $2YES$2,\n $2CLANG_CXX_LIBRARY$2: $2libc++$2,\n $2MACOSX_DEPLOYMENT_TARGET$2: $210.7$2,\n },\n $2msvs_settings$2: {\n $2VCCLCompilerTool$2: { $2ExceptionHandling$2: 1 },\n },']
|
||||||
|
]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ConfigFileOperations = {
|
||||||
|
'package.json': [
|
||||||
|
[/([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'],
|
||||||
|
[/[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '']
|
||||||
|
],
|
||||||
|
'binding.gyp': [
|
||||||
|
[/([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'<!(node -p "require(\\\'node-addon-api\\\').include_dir")\','],
|
||||||
|
[/([ ]*)"include_dirs": \[/g, '$1"include_dirs": [\n$1 "<!(node -p \'require(\\"node-addon-api\\").include_dir\')",'],
|
||||||
|
[/[ ]*("|')<!\(node -e ("|'|\\"|\\')require\(("|'|\\"|\\')nan("|'|\\"|\\')\)("|'|\\"|\\')\)("|')(,|)[\r\n]/g, ''],
|
||||||
|
[/([ ]*)("|')target_name("|'): ("|')(.+?)("|'),/g, '$1$2target_name$2: $4$5$6,\n $2cflags!$2: [ $2-fno-exceptions$2 ],\n $2cflags_cc!$2: [ $2-fno-exceptions$2 ],\n $2defines$2: [ $2NAPI_DISABLE_CPP_EXCEPTIONS$2 ],\n $2conditions$2: [\n [\'OS=="win"\', { $2defines$2: [ $2_HAS_EXCEPTIONS=1$2 ] }]\n ]']
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceFileOperations = [
|
||||||
|
[/Nan::SetMethod\(target,[\s]*"(.*)"[\s]*,[\s]*([^)]+)\)/g, 'exports.Set(Napi::String::New(env, "$1"), Napi::Function::New(env, $2))'],
|
||||||
|
|
||||||
|
[/v8::Local<v8::FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {'],
|
||||||
|
[/Local<FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);\s+(\w+)\.Reset\((\1)\);\s+\1->SetClassName\((Nan::String::New|Nan::New<(v8::)*String>)\("(.+?)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$6", {'],
|
||||||
|
[/Local<FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {'],
|
||||||
|
[/Nan::New<v8::FunctionTemplate>\(([\w\d:]+)\)->GetFunction\(\)/g, 'Napi::Function::New(env, $1)'],
|
||||||
|
[/Nan::New<FunctionTemplate>\(([\w\d:]+)\)->GetFunction()/g, 'Napi::Function::New(env, $1);'],
|
||||||
|
[/Nan::New<v8::FunctionTemplate>\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)'],
|
||||||
|
[/Nan::New<FunctionTemplate>\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)'],
|
||||||
|
|
||||||
|
// FunctionTemplate to FunctionReference
|
||||||
|
[/Nan::Persistent<(v8::)*FunctionTemplate>/g, 'Napi::FunctionReference'],
|
||||||
|
[/Nan::Persistent<(v8::)*Function>/g, 'Napi::FunctionReference'],
|
||||||
|
[/v8::Local<v8::FunctionTemplate>/g, 'Napi::FunctionReference'],
|
||||||
|
[/Local<FunctionTemplate>/g, 'Napi::FunctionReference'],
|
||||||
|
[/v8::FunctionTemplate/g, 'Napi::FunctionReference'],
|
||||||
|
[/FunctionTemplate/g, 'Napi::FunctionReference'],
|
||||||
|
|
||||||
|
[/([ ]*)Nan::SetPrototypeMethod\(\w+, "(\w+)", (\w+)\);/g, '$1InstanceMethod("$2", &$3),'],
|
||||||
|
[/([ ]*)(?:\w+\.Reset\(\w+\);\s+)?\(target\)\.Set\("(\w+)",\s*Nan::GetFunction\((\w+)\)\);/gm,
|
||||||
|
'});\n\n' +
|
||||||
|
'$1constructor = Napi::Persistent($3);\n' +
|
||||||
|
'$1constructor.SuppressDestruct();\n' +
|
||||||
|
'$1target.Set("$2", $3);'],
|
||||||
|
|
||||||
|
// TODO: Other attribute combinations
|
||||||
|
[/static_cast<PropertyAttribute>\(ReadOnly\s*\|\s*DontDelete\)/gm,
|
||||||
|
'static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)'],
|
||||||
|
|
||||||
|
[/([\w\d:<>]+?)::Cast\((.+?)\)/g, '$2.As<$1>()'],
|
||||||
|
|
||||||
|
[/\*Nan::Utf8String\(([^)]+)\)/g, '$1->As<Napi::String>().Utf8Value().c_str()'],
|
||||||
|
[/Nan::Utf8String +(\w+)\(([^)]+)\)/g, 'std::string $1 = $2.As<Napi::String>()'],
|
||||||
|
[/Nan::Utf8String/g, 'std::string'],
|
||||||
|
|
||||||
|
[/v8::String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)'],
|
||||||
|
[/String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)'],
|
||||||
|
[/\.length\(\)/g, '.Length()'],
|
||||||
|
|
||||||
|
[/Nan::MakeCallback\(([^,]+),[\s\\]+([^,]+),/gm, '$2.MakeCallback($1,'],
|
||||||
|
|
||||||
|
[/class\s+(\w+)\s*:\s*public\s+Nan::ObjectWrap/g, 'class $1 : public Napi::ObjectWrap<$1>'],
|
||||||
|
[/(\w+)\(([^)]*)\)\s*:\s*Nan::ObjectWrap\(\)\s*(,)?/gm, '$1($2) : Napi::ObjectWrap<$1>()$3'],
|
||||||
|
|
||||||
|
// HandleOKCallback to OnOK
|
||||||
|
[/HandleOKCallback/g, 'OnOK'],
|
||||||
|
// HandleErrorCallback to OnError
|
||||||
|
[/HandleErrorCallback/g, 'OnError'],
|
||||||
|
|
||||||
|
// ex. .As<Function>() to .As<Napi::Object>()
|
||||||
|
[/\.As<v8::(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As<Napi::$1>()'],
|
||||||
|
[/\.As<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As<Napi::$1>()'],
|
||||||
|
|
||||||
|
// ex. Nan::New<Number>(info[0]) to Napi::Number::New(info[0])
|
||||||
|
[/Nan::New<(v8::)*Integer>\((.+?)\)/g, 'Napi::Number::New(env, $2)'],
|
||||||
|
[/Nan::New\(([0-9.]+)\)/g, 'Napi::Number::New(env, $1)'],
|
||||||
|
[/Nan::New<(v8::)*String>\("(.+?)"\)/g, 'Napi::String::New(env, "$2")'],
|
||||||
|
[/Nan::New\("(.+?)"\)/g, 'Napi::String::New(env, "$1")'],
|
||||||
|
[/Nan::New<(v8::)*(.+?)>\(\)/g, 'Napi::$2::New(env)'],
|
||||||
|
[/Nan::New<(.+?)>\(\)/g, 'Napi::$1::New(env)'],
|
||||||
|
[/Nan::New<(v8::)*(.+?)>\(/g, 'Napi::$2::New(env, '],
|
||||||
|
[/Nan::New<(.+?)>\(/g, 'Napi::$1::New(env, '],
|
||||||
|
[/Nan::NewBuffer\(/g, 'Napi::Buffer<char>::New(env, '],
|
||||||
|
// TODO: Properly handle this
|
||||||
|
[/Nan::New\(/g, 'Napi::New(env, '],
|
||||||
|
|
||||||
|
[/\.IsInt32\(\)/g, '.IsNumber()'],
|
||||||
|
[/->IsInt32\(\)/g, '.IsNumber()'],
|
||||||
|
|
||||||
|
[/(.+?)->BooleanValue\(\)/g, '$1.As<Napi::Boolean>().Value()'],
|
||||||
|
[/(.+?)->Int32Value\(\)/g, '$1.As<Napi::Number>().Int32Value()'],
|
||||||
|
[/(.+?)->Uint32Value\(\)/g, '$1.As<Napi::Number>().Uint32Value()'],
|
||||||
|
[/(.+?)->IntegerValue\(\)/g, '$1.As<Napi::Number>().Int64Value()'],
|
||||||
|
[/(.+?)->NumberValue\(\)/g, '$1.As<Napi::Number>().DoubleValue()'],
|
||||||
|
|
||||||
|
// ex. Nan::To<bool>(info[0]) to info[0].Value()
|
||||||
|
[/Nan::To<v8::(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To<Napi::$1>()'],
|
||||||
|
[/Nan::To<(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To<Napi::$1>()'],
|
||||||
|
// ex. Nan::To<bool>(info[0]) to info[0].As<Napi::Boolean>().Value()
|
||||||
|
[/Nan::To<bool>\((.+?)\)/g, '$1.As<Napi::Boolean>().Value()'],
|
||||||
|
// ex. Nan::To<int>(info[0]) to info[0].As<Napi::Number>().Int32Value()
|
||||||
|
[/Nan::To<int>\((.+?)\)/g, '$1.As<Napi::Number>().Int32Value()'],
|
||||||
|
// ex. Nan::To<int32_t>(info[0]) to info[0].As<Napi::Number>().Int32Value()
|
||||||
|
[/Nan::To<int32_t>\((.+?)\)/g, '$1.As<Napi::Number>().Int32Value()'],
|
||||||
|
// ex. Nan::To<uint32_t>(info[0]) to info[0].As<Napi::Number>().Uint32Value()
|
||||||
|
[/Nan::To<uint32_t>\((.+?)\)/g, '$1.As<Napi::Number>().Uint32Value()'],
|
||||||
|
// ex. Nan::To<int64_t>(info[0]) to info[0].As<Napi::Number>().Int64Value()
|
||||||
|
[/Nan::To<int64_t>\((.+?)\)/g, '$1.As<Napi::Number>().Int64Value()'],
|
||||||
|
// ex. Nan::To<float>(info[0]) to info[0].As<Napi::Number>().FloatValue()
|
||||||
|
[/Nan::To<float>\((.+?)\)/g, '$1.As<Napi::Number>().FloatValue()'],
|
||||||
|
// ex. Nan::To<double>(info[0]) to info[0].As<Napi::Number>().DoubleValue()
|
||||||
|
[/Nan::To<double>\((.+?)\)/g, '$1.As<Napi::Number>().DoubleValue()'],
|
||||||
|
|
||||||
|
[/Nan::New\((\w+)\)->HasInstance\((\w+)\)/g, '$2.InstanceOf($1.Value())'],
|
||||||
|
|
||||||
|
[/Nan::Has\(([^,]+),\s*/gm, '($1).Has('],
|
||||||
|
[/\.Has\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Has($1)'],
|
||||||
|
[/\.Has\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Has($1)'],
|
||||||
|
|
||||||
|
[/Nan::Get\(([^,]+),\s*/gm, '($1).Get('],
|
||||||
|
[/\.Get\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Get($1)'],
|
||||||
|
[/\.Get\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Get($1)'],
|
||||||
|
|
||||||
|
[/Nan::Set\(([^,]+),\s*/gm, '($1).Set('],
|
||||||
|
[/\.Set\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\s*,/gm, '.Set($1,'],
|
||||||
|
[/\.Set\([\s|\\]*Nan::New\(([^)]+)\)\s*,/gm, '.Set($1,'],
|
||||||
|
|
||||||
|
// ex. node::Buffer::HasInstance(info[0]) to info[0].IsBuffer()
|
||||||
|
[/node::Buffer::HasInstance\((.+?)\)/g, '$1.IsBuffer()'],
|
||||||
|
// ex. node::Buffer::Length(info[0]) to info[0].Length()
|
||||||
|
[/node::Buffer::Length\((.+?)\)/g, '$1.As<Napi::Buffer<char>>().Length()'],
|
||||||
|
// ex. node::Buffer::Data(info[0]) to info[0].Data()
|
||||||
|
[/node::Buffer::Data\((.+?)\)/g, '$1.As<Napi::Buffer<char>>().Data()'],
|
||||||
|
[/Nan::CopyBuffer\(/g, 'Napi::Buffer::Copy(env, '],
|
||||||
|
|
||||||
|
// Nan::AsyncQueueWorker(worker)
|
||||||
|
[/Nan::AsyncQueueWorker\((.+)\);/g, '$1.Queue();'],
|
||||||
|
[/Nan::(Undefined|Null|True|False)\(\)/g, 'env.$1()'],
|
||||||
|
|
||||||
|
// Nan::ThrowError(error) to Napi::Error::New(env, error).ThrowAsJavaScriptException()
|
||||||
|
[/([ ]*)return Nan::Throw(\w*?)Error\((.+?)\);/g, '$1Napi::$2Error::New(env, $3).ThrowAsJavaScriptException();\n$1return env.Null();'],
|
||||||
|
[/Nan::Throw(\w*?)Error\((.+?)\);\n(\s*)return;/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n$3return env.Null();'],
|
||||||
|
[/Nan::Throw(\w*?)Error\((.+?)\);/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n'],
|
||||||
|
// Nan::RangeError(error) to Napi::RangeError::New(env, error)
|
||||||
|
[/Nan::(\w*?)Error\((.+)\)/g, 'Napi::$1Error::New(env, $2)'],
|
||||||
|
|
||||||
|
[/Nan::Set\((.+?),\n* *(.+?),\n* *(.+?),\n* *(.+?)\)/g, '$1.Set($2, $3, $4)'],
|
||||||
|
|
||||||
|
[/Nan::(Escapable)?HandleScope\s+(\w+)\s*;/g, 'Napi::$1HandleScope $2(env);'],
|
||||||
|
[/Nan::(Escapable)?HandleScope/g, 'Napi::$1HandleScope'],
|
||||||
|
[/Nan::ForceSet\(([^,]+), ?/g, '$1->DefineProperty('],
|
||||||
|
[/\.ForceSet\(Napi::String::New\(env, "(\w+)"\),\s*?/g, '.DefineProperty("$1", '],
|
||||||
|
// [ /Nan::GetPropertyNames\(([^,]+)\)/, '$1->GetPropertyNames()' ],
|
||||||
|
[/Nan::Equals\(([^,]+),/g, '$1.StrictEquals('],
|
||||||
|
|
||||||
|
[/(.+)->Set\(/g, '$1.Set('],
|
||||||
|
|
||||||
|
[/Nan::Callback/g, 'Napi::FunctionReference'],
|
||||||
|
|
||||||
|
[/Nan::Persistent<Object>/g, 'Napi::ObjectReference'],
|
||||||
|
[/Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target/g, 'Napi::Env& env, Napi::Object& target'],
|
||||||
|
|
||||||
|
[/(\w+)\*\s+(\w+)\s*=\s*Nan::ObjectWrap::Unwrap<\w+>\(info\.This\(\)\);/g, '$1* $2 = this;'],
|
||||||
|
[/Nan::ObjectWrap::Unwrap<(\w+)>\((.*)\);/g, '$2.Unwrap<$1>();'],
|
||||||
|
|
||||||
|
[/Nan::NAN_METHOD_RETURN_TYPE/g, 'void'],
|
||||||
|
[/NAN_INLINE/g, 'inline'],
|
||||||
|
|
||||||
|
[/Nan::NAN_METHOD_ARGS_TYPE/g, 'const Napi::CallbackInfo&'],
|
||||||
|
[/NAN_METHOD\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'],
|
||||||
|
[/static\s*NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'],
|
||||||
|
[/NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'],
|
||||||
|
[/static\s*NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)'],
|
||||||
|
[/NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)'],
|
||||||
|
[/void Init\((v8::)*Local<(v8::)*Object> exports\)/g, 'Napi::Object Init(Napi::Env env, Napi::Object exports)'],
|
||||||
|
[/NAN_MODULE_INIT\(([\w\d:]+?)\);/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports);'],
|
||||||
|
[/NAN_MODULE_INIT\(([\w\d:]+?)\)/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports)'],
|
||||||
|
|
||||||
|
[/::(Init(?:ialize)?)\(target\)/g, '::$1(env, target, module)'],
|
||||||
|
[/constructor_template/g, 'constructor'],
|
||||||
|
|
||||||
|
[/Nan::FunctionCallbackInfo<(v8::)?Value>[ ]*& [ ]*info\)[ ]*{\n*([ ]*)/gm, 'Napi::CallbackInfo& info) {\n$2Napi::Env env = info.Env();\n$2'],
|
||||||
|
[/Nan::FunctionCallbackInfo<(v8::)*Value>\s*&\s*info\);/g, 'Napi::CallbackInfo& info);'],
|
||||||
|
[/Nan::FunctionCallbackInfo<(v8::)*Value>\s*&/g, 'Napi::CallbackInfo&'],
|
||||||
|
|
||||||
|
[/Buffer::HasInstance\(([^)]+)\)/g, '$1.IsBuffer()'],
|
||||||
|
|
||||||
|
[/info\[(\d+)\]->/g, 'info[$1].'],
|
||||||
|
[/info\[([\w\d]+)\]->/g, 'info[$1].'],
|
||||||
|
[/info\.This\(\)->/g, 'info.This().'],
|
||||||
|
[/->Is(Object|String|Int32|Number)\(\)/g, '.Is$1()'],
|
||||||
|
[/info.GetReturnValue\(\).SetUndefined\(\)/g, 'return env.Undefined()'],
|
||||||
|
[/info\.GetReturnValue\(\)\.Set\(((\n|.)+?)\);/g, 'return $1;'],
|
||||||
|
|
||||||
|
// ex. Local<Value> to Napi::Value
|
||||||
|
[/v8::Local<v8::(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1'],
|
||||||
|
[/Local<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1'],
|
||||||
|
|
||||||
|
// Declare an env in helper functions that take a Napi::Value
|
||||||
|
[/(\w+)\(Napi::Value (\w+)(,\s*[^()]+)?\)\s*{\n*([ ]*)/gm, '$1(Napi::Value $2$3) {\n$4Napi::Env env = $2.Env();\n$4'],
|
||||||
|
|
||||||
|
// delete #include <node.h> and/or <v8.h>
|
||||||
|
[/#include +(<|")(?:node|nan).h("|>)/g, '#include $1napi.h$2\n#include $1uv.h$2'],
|
||||||
|
// NODE_MODULE to NODE_API_MODULE
|
||||||
|
[/NODE_MODULE/g, 'NODE_API_MODULE'],
|
||||||
|
[/Nan::/g, 'Napi::'],
|
||||||
|
[/nan.h/g, 'napi.h'],
|
||||||
|
|
||||||
|
// delete .FromJust()
|
||||||
|
[/\.FromJust\(\)/g, ''],
|
||||||
|
// delete .ToLocalCheck()
|
||||||
|
[/\.ToLocalChecked\(\)/g, ''],
|
||||||
|
[/^.*->SetInternalFieldCount\(.*$/gm, ''],
|
||||||
|
|
||||||
|
// replace using node; and/or using v8; to using Napi;
|
||||||
|
[/using (node|v8);/g, 'using Napi;'],
|
||||||
|
[/using namespace (node|Nan|v8);/g, 'using namespace Napi;'],
|
||||||
|
// delete using v8::Local;
|
||||||
|
[/using v8::Local;\n/g, ''],
|
||||||
|
// replace using v8::XXX; with using Napi::XXX
|
||||||
|
[/using v8::([A-Za-z]+);/g, 'using Napi::$1;']
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
const paths = listFiles(dir);
|
||||||
|
paths.forEach(function (dirEntry) {
|
||||||
|
const filename = dirEntry.split('\\').pop().split('/').pop();
|
||||||
|
|
||||||
|
// Check whether the file is a source file or a config file
|
||||||
|
// then execute function accordingly
|
||||||
|
const sourcePattern = /.+\.h|.+\.cc|.+\.cpp/;
|
||||||
|
if (sourcePattern.test(filename)) {
|
||||||
|
convertFile(dirEntry, SourceFileOperations);
|
||||||
|
} else if (ConfigFileOperations[filename] != null) {
|
||||||
|
convertFile(dirEntry, ConfigFileOperations[filename]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function listFiles (dir, filelist) {
|
||||||
|
const files = fs.readdirSync(dir);
|
||||||
|
filelist = filelist || [];
|
||||||
|
files.forEach(function (file) {
|
||||||
|
if (file === 'node_modules') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.statSync(path.join(dir, file)).isDirectory()) {
|
||||||
|
filelist = listFiles(path.join(dir, file), filelist);
|
||||||
|
} else {
|
||||||
|
filelist.push(path.join(dir, file));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convert (content, operations) {
|
||||||
|
for (let i = 0; i < operations.length; i++) {
|
||||||
|
const operation = operations[i];
|
||||||
|
content = content.replace(operation[0], operation[1]);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertFile (fileName, operations) {
|
||||||
|
fs.readFile(fileName, 'utf-8', function (err, file) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
file = convert(file, operations);
|
||||||
|
|
||||||
|
fs.writeFile(fileName, file, function (err) {
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
62
node_modules/bcrypt/package.json
generated
vendored
Normal file
62
node_modules/bcrypt/package.json
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"name": "bcrypt",
|
||||||
|
"description": "A bcrypt library for NodeJS.",
|
||||||
|
"keywords": [
|
||||||
|
"bcrypt",
|
||||||
|
"password",
|
||||||
|
"auth",
|
||||||
|
"authentication",
|
||||||
|
"encryption",
|
||||||
|
"crypt",
|
||||||
|
"crypto"
|
||||||
|
],
|
||||||
|
"main": "./bcrypt",
|
||||||
|
"version": "6.0.0",
|
||||||
|
"author": "Nick Campbell (https://github.com/ncb000gt)",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/kelektiv/node.bcrypt.js.git"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/kelektiv/node.bcrypt.js/issues"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest",
|
||||||
|
"install": "node-gyp-build",
|
||||||
|
"build": "prebuildify --napi --tag-libc --strip"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^8.3.0",
|
||||||
|
"node-gyp-build": "^4.8.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"prebuildify": "^6.0.1"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
"Antonio Salazar Cardozo <savedfastcool@gmail.com> (https://github.com/Shadowfiend)",
|
||||||
|
"Van Nguyen <the.gol.effect@gmail.com> (https://github.com/thegoleffect)",
|
||||||
|
"David Trejo <david@dtrejo.com> (https://github.com/dtrejo)",
|
||||||
|
"Ben Glow <glen.low@pixelglow.com> (https://github.com/pixelglow)",
|
||||||
|
"NewITFarmer.com <> (https://github.com/newitfarmer)",
|
||||||
|
"Alfred Westerveld <alfredwesterveld@gmail.com> (https://github.com/alfredwesterveld)",
|
||||||
|
"Vincent Côté-Roy <vincentcr@gmail.com> (https://github.com/vincentcr)",
|
||||||
|
"Lloyd Hilaiel <lloyd@hilaiel.com> (https://github.com/lloyd)",
|
||||||
|
"Roman Shtylman <shtylman@gmail.com> (https://github.com/shtylman)",
|
||||||
|
"Vadim Graboys <dimva13@gmail.com> (https://github.com/vadimg)",
|
||||||
|
"Ben Noorduis <> (https://github.com/bnoordhuis)",
|
||||||
|
"Nate Rajlich <nathan@tootallnate.net> (https://github.com/tootallnate)",
|
||||||
|
"Sean McArthur <sean.monstar@gmail.com> (https://github.com/seanmonstar)",
|
||||||
|
"Fanie Oosthuysen <fanie.oosthuysen@gmail.com> (https://github.com/weareu)",
|
||||||
|
"Amitosh Swain Mahapatra <amitosh.swain@gmail.com> (https://github.com/Agathver)",
|
||||||
|
"Corbin Crutchley <crutchcorn@gmail.com> (https://github.com/crutchcorn)",
|
||||||
|
"Nicola Del Gobbo <nicoladelgobbo@gmail.com> (https://github.com/NickNaso)"
|
||||||
|
],
|
||||||
|
"binary": {
|
||||||
|
"module_name": "bcrypt_lib"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
node_modules/bcrypt/prebuilds/darwin-arm64/bcrypt.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/darwin-arm64/bcrypt.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/darwin-x64/bcrypt.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/darwin-x64/bcrypt.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-arm/bcrypt.glibc.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-arm/bcrypt.glibc.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-arm/bcrypt.musl.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-arm/bcrypt.musl.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-arm64/bcrypt.glibc.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-arm64/bcrypt.glibc.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-arm64/bcrypt.musl.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-arm64/bcrypt.musl.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-x64/bcrypt.glibc.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-x64/bcrypt.glibc.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/linux-x64/bcrypt.musl.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/linux-x64/bcrypt.musl.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/win32-arm64/bcrypt.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/win32-arm64/bcrypt.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/bcrypt/prebuilds/win32-x64/bcrypt.node
generated
vendored
Normal file
BIN
node_modules/bcrypt/prebuilds/win32-x64/bcrypt.node
generated
vendored
Normal file
Binary file not shown.
45
node_modules/bcrypt/promises.js
generated
vendored
Normal file
45
node_modules/bcrypt/promises.js
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
let Promise = global.Promise;
|
||||||
|
|
||||||
|
/// encapsulate a method with a node-style callback in a Promise
|
||||||
|
/// @param {object} 'this' of the encapsulated function
|
||||||
|
/// @param {function} function to be encapsulated
|
||||||
|
/// @param {Array-like} args to be passed to the called function
|
||||||
|
/// @return {Promise} a Promise encapsulating the function
|
||||||
|
function promise(fn, context, args) {
|
||||||
|
if (!Array.isArray(args)) {
|
||||||
|
args = Array.prototype.slice.call(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof fn !== 'function') {
|
||||||
|
return Promise.reject(new Error('fn must be a function'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
args.push((err, data) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fn.apply(context, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param {err} the error to be thrown
|
||||||
|
function reject(err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// changes the promise implementation that bcrypt uses
|
||||||
|
/// @param {Promise} the implementation to use
|
||||||
|
function use(promise) {
|
||||||
|
Promise = promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
promise,
|
||||||
|
reject,
|
||||||
|
use
|
||||||
|
}
|
||||||
315
node_modules/bcrypt/src/bcrypt.cc
generated
vendored
Normal file
315
node_modules/bcrypt/src/bcrypt.cc
generated
vendored
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/* $OpenBSD: bcrypt.c,v 1.31 2014/03/22 23:02:03 tedu Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1997 Niels Provos <provos@umich.edu>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This password hashing algorithm was designed by David Mazieres
|
||||||
|
* <dm@lcs.mit.edu> and works as follows:
|
||||||
|
*
|
||||||
|
* 1. state := InitState ()
|
||||||
|
* 2. state := ExpandKey (state, salt, password)
|
||||||
|
* 3. REPEAT rounds:
|
||||||
|
* state := ExpandKey (state, 0, password)
|
||||||
|
* state := ExpandKey (state, 0, salt)
|
||||||
|
* 4. ctext := "OrpheanBeholderScryDoubt"
|
||||||
|
* 5. REPEAT 64:
|
||||||
|
* ctext := Encrypt_ECB (state, ctext);
|
||||||
|
* 6. RETURN Concatenate (salt, ctext);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "node_blf.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#if !defined(__APPLE__) && !defined(__MACH__)
|
||||||
|
//#include "bsd/stdlib.h"
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
/* This implementation is adaptable to current computing power.
|
||||||
|
* You can have up to 2^31 rounds which should be enough for some
|
||||||
|
* time to come.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
|
||||||
|
static void decode_base64(u_int8_t *, u_int16_t, u_int8_t *);
|
||||||
|
|
||||||
|
const static char* error = ":";
|
||||||
|
|
||||||
|
const static u_int8_t Base64Code[] =
|
||||||
|
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
const static u_int8_t index_64[128] = {
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
|
||||||
|
56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||||
|
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||||
|
255, 255, 255, 255, 255, 255, 28, 29, 30,
|
||||||
|
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||||
|
51, 52, 53, 255, 255, 255, 255, 255
|
||||||
|
};
|
||||||
|
#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])
|
||||||
|
|
||||||
|
static void
|
||||||
|
decode_base64(u_int8_t *buffer, u_int16_t len, u_int8_t *data)
|
||||||
|
{
|
||||||
|
u_int8_t *bp = buffer;
|
||||||
|
u_int8_t *p = data;
|
||||||
|
u_int8_t c1, c2, c3, c4;
|
||||||
|
while (bp < buffer + len) {
|
||||||
|
c1 = CHAR64(*p);
|
||||||
|
c2 = CHAR64(*(p + 1));
|
||||||
|
|
||||||
|
/* Invalid data */
|
||||||
|
if (c1 == 255 || c2 == 255)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||||
|
if (bp >= buffer + len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
c3 = CHAR64(*(p + 2));
|
||||||
|
if (c3 == 255)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
|
||||||
|
if (bp >= buffer + len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
c4 = CHAR64(*(p + 3));
|
||||||
|
if (c4 == 255)
|
||||||
|
break;
|
||||||
|
*bp++ = ((c3 & 0x03) << 6) | c4;
|
||||||
|
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
encode_salt(char *salt, u_int8_t *csalt, char minor, u_int16_t clen, u_int8_t logr)
|
||||||
|
{
|
||||||
|
salt[0] = '$';
|
||||||
|
salt[1] = BCRYPT_VERSION;
|
||||||
|
salt[2] = minor;
|
||||||
|
salt[3] = '$';
|
||||||
|
|
||||||
|
// Max rounds are 31
|
||||||
|
snprintf(salt + 4, 4, "%2.2u$", logr & 0x001F);
|
||||||
|
|
||||||
|
encode_base64((u_int8_t *) salt + 7, csalt, clen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Generates a salt for this version of crypt.
|
||||||
|
Since versions may change. Keeping this here
|
||||||
|
seems sensible.
|
||||||
|
from: http://mail-index.netbsd.org/tech-crypto/2002/05/24/msg000204.html
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
bcrypt_gensalt(char minor, u_int8_t log_rounds, u_int8_t *seed, char *gsalt)
|
||||||
|
{
|
||||||
|
if (log_rounds < 4)
|
||||||
|
log_rounds = 4;
|
||||||
|
else if (log_rounds > 31)
|
||||||
|
log_rounds = 31;
|
||||||
|
|
||||||
|
encode_salt(gsalt, seed, minor, BCRYPT_MAXSALT, log_rounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We handle $Vers$log2(NumRounds)$salt+passwd$
|
||||||
|
i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
|
||||||
|
|
||||||
|
void
|
||||||
|
bcrypt(const char *key, size_t key_len, const char *salt, char *encrypted)
|
||||||
|
{
|
||||||
|
blf_ctx state;
|
||||||
|
u_int32_t rounds, i, k;
|
||||||
|
u_int16_t j;
|
||||||
|
u_int8_t salt_len, logr, minor;
|
||||||
|
u_int8_t ciphertext[4 * BCRYPT_BLOCKS+1] = "OrpheanBeholderScryDoubt";
|
||||||
|
u_int8_t csalt[BCRYPT_MAXSALT];
|
||||||
|
u_int32_t cdata[BCRYPT_BLOCKS];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Discard "$" identifier */
|
||||||
|
salt++;
|
||||||
|
|
||||||
|
if (*salt > BCRYPT_VERSION) {
|
||||||
|
/* How do I handle errors ? Return ':' */
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for minor versions */
|
||||||
|
if (salt[1] != '$') {
|
||||||
|
switch (salt[1]) {
|
||||||
|
case 'a': /* 'ab' should not yield the same as 'abab' */
|
||||||
|
case 'b': /* cap input length at 72 bytes */
|
||||||
|
minor = salt[1];
|
||||||
|
salt++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
minor = 0;
|
||||||
|
|
||||||
|
/* Discard version + "$" identifier */
|
||||||
|
salt += 2;
|
||||||
|
|
||||||
|
if (salt[2] != '$') {
|
||||||
|
/* Out of sync with passwd entry */
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computer power doesn't increase linear, 2^x should be fine */
|
||||||
|
n = atoi(salt);
|
||||||
|
if (n > 31 || n < 0) {
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logr = (u_int8_t)n;
|
||||||
|
if ((rounds = (u_int32_t) 1 << logr) < BCRYPT_MINROUNDS) {
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Discard num rounds + "$" identifier */
|
||||||
|
salt += 3;
|
||||||
|
|
||||||
|
if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
|
||||||
|
strcpy(encrypted, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We dont want the base64 salt but the raw data */
|
||||||
|
decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt);
|
||||||
|
salt_len = BCRYPT_MAXSALT;
|
||||||
|
if (minor <= 'a')
|
||||||
|
key_len = (u_int8_t)(key_len + (minor >= 'a' ? 1 : 0));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* cap key_len at the actual maximum supported
|
||||||
|
* length here to avoid integer wraparound */
|
||||||
|
if (key_len > 72)
|
||||||
|
key_len = 72;
|
||||||
|
key_len++; /* include the NUL */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Setting up S-Boxes and Subkeys */
|
||||||
|
Blowfish_initstate(&state);
|
||||||
|
Blowfish_expandstate(&state, csalt, salt_len,
|
||||||
|
(u_int8_t *) key, key_len);
|
||||||
|
for (k = 0; k < rounds; k++) {
|
||||||
|
Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
|
||||||
|
Blowfish_expand0state(&state, csalt, salt_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This can be precomputed later */
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < BCRYPT_BLOCKS; i++)
|
||||||
|
cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
|
||||||
|
|
||||||
|
/* Now do the encryption */
|
||||||
|
for (k = 0; k < 64; k++)
|
||||||
|
blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
|
||||||
|
|
||||||
|
for (i = 0; i < BCRYPT_BLOCKS; i++) {
|
||||||
|
ciphertext[4 * i + 3] = cdata[i] & 0xff;
|
||||||
|
cdata[i] = cdata[i] >> 8;
|
||||||
|
ciphertext[4 * i + 2] = cdata[i] & 0xff;
|
||||||
|
cdata[i] = cdata[i] >> 8;
|
||||||
|
ciphertext[4 * i + 1] = cdata[i] & 0xff;
|
||||||
|
cdata[i] = cdata[i] >> 8;
|
||||||
|
ciphertext[4 * i + 0] = cdata[i] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
encrypted[i++] = '$';
|
||||||
|
encrypted[i++] = BCRYPT_VERSION;
|
||||||
|
if (minor)
|
||||||
|
encrypted[i++] = minor;
|
||||||
|
encrypted[i++] = '$';
|
||||||
|
|
||||||
|
snprintf(encrypted + i, 4, "%2.2u$", logr & 0x001F);
|
||||||
|
|
||||||
|
encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
|
||||||
|
encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
|
||||||
|
4 * BCRYPT_BLOCKS - 1);
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
memset(ciphertext, 0, sizeof(ciphertext));
|
||||||
|
memset(csalt, 0, sizeof(csalt));
|
||||||
|
memset(cdata, 0, sizeof(cdata));
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t bcrypt_get_rounds(const char * hash)
|
||||||
|
{
|
||||||
|
/* skip past the leading "$" */
|
||||||
|
if (!hash || *(hash++) != '$') return 0;
|
||||||
|
|
||||||
|
/* skip past version */
|
||||||
|
if (0 == (*hash++)) return 0;
|
||||||
|
if (*hash && *hash != '$') hash++;
|
||||||
|
if (*hash++ != '$') return 0;
|
||||||
|
|
||||||
|
return atoi(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)
|
||||||
|
{
|
||||||
|
u_int8_t *bp = buffer;
|
||||||
|
u_int8_t *p = data;
|
||||||
|
u_int8_t c1, c2;
|
||||||
|
while (p < data + len) {
|
||||||
|
c1 = *p++;
|
||||||
|
*bp++ = Base64Code[(c1 >> 2)];
|
||||||
|
c1 = (c1 & 0x03) << 4;
|
||||||
|
if (p >= data + len) {
|
||||||
|
*bp++ = Base64Code[c1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c2 = *p++;
|
||||||
|
c1 |= (c2 >> 4) & 0x0f;
|
||||||
|
*bp++ = Base64Code[c1];
|
||||||
|
c1 = (c2 & 0x0f) << 2;
|
||||||
|
if (p >= data + len) {
|
||||||
|
*bp++ = Base64Code[c1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c2 = *p++;
|
||||||
|
c1 |= (c2 >> 6) & 0x03;
|
||||||
|
*bp++ = Base64Code[c1];
|
||||||
|
*bp++ = Base64Code[c2 & 0x3f];
|
||||||
|
}
|
||||||
|
*bp = '\0';
|
||||||
|
}
|
||||||
288
node_modules/bcrypt/src/bcrypt_node.cc
generated
vendored
Normal file
288
node_modules/bcrypt/src/bcrypt_node.cc
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
#define NAPI_VERSION 3
|
||||||
|
|
||||||
|
#include <napi.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdlib.h> // atoi
|
||||||
|
|
||||||
|
#include "node_blf.h"
|
||||||
|
|
||||||
|
#define NODE_LESS_THAN (!(NODE_VERSION_AT_LEAST(0, 5, 4)))
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool ValidateSalt(const char* salt) {
|
||||||
|
|
||||||
|
if (!salt || *salt != '$') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard $
|
||||||
|
salt++;
|
||||||
|
|
||||||
|
if (*salt > BCRYPT_VERSION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (salt[1] != '$') {
|
||||||
|
switch (salt[1]) {
|
||||||
|
case 'a':
|
||||||
|
case 'b':
|
||||||
|
salt++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard version + $
|
||||||
|
salt += 2;
|
||||||
|
|
||||||
|
if (salt[2] != '$') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = atoi(salt);
|
||||||
|
if (n > 31 || n < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((uint8_t)1 << (uint8_t)n) < BCRYPT_MINROUNDS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
salt += 3;
|
||||||
|
if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char ToCharVersion(const std::string& str) {
|
||||||
|
return str[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SALT GENERATION */
|
||||||
|
|
||||||
|
class SaltAsyncWorker : public Napi::AsyncWorker {
|
||||||
|
public:
|
||||||
|
SaltAsyncWorker(const Napi::Function& callback, const std::string& seed, ssize_t rounds, char minor_ver)
|
||||||
|
: Napi::AsyncWorker(callback, "bcrypt:SaltAsyncWorker"), seed(seed), rounds(rounds), minor_ver(minor_ver) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~SaltAsyncWorker() {}
|
||||||
|
|
||||||
|
void Execute() {
|
||||||
|
bcrypt_gensalt(minor_ver, rounds, (u_int8_t *)&seed[0], salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnOK() {
|
||||||
|
Napi::HandleScope scope(Env());
|
||||||
|
Callback().Call({Env().Undefined(), Napi::String::New(Env(), salt)});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string seed;
|
||||||
|
ssize_t rounds;
|
||||||
|
char minor_ver;
|
||||||
|
char salt[_SALT_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Value GenerateSalt(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
if (info.Length() < 4) {
|
||||||
|
throw Napi::TypeError::New(env, "4 arguments expected");
|
||||||
|
}
|
||||||
|
if (!info[0].IsString()) {
|
||||||
|
throw Napi::TypeError::New(env, "First argument must be a string");
|
||||||
|
}
|
||||||
|
if (!info[2].IsBuffer() || (info[2].As<Napi::Buffer<char>>()).Length() != 16) {
|
||||||
|
throw Napi::TypeError::New(env, "Second argument must be a 16 byte Buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char minor_ver = ToCharVersion(info[0].As<Napi::String>());
|
||||||
|
const int32_t rounds = info[1].As<Napi::Number>();
|
||||||
|
Napi::Buffer<char> seed = info[2].As<Napi::Buffer<char>>();
|
||||||
|
Napi::Function callback = info[3].As<Napi::Function>();
|
||||||
|
SaltAsyncWorker* saltWorker = new SaltAsyncWorker(callback, std::string(seed.Data(), 16), rounds, minor_ver);
|
||||||
|
saltWorker->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value GenerateSaltSync(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
if (info.Length() < 3) {
|
||||||
|
throw Napi::TypeError::New(env, "3 arguments expected");
|
||||||
|
}
|
||||||
|
if (!info[0].IsString()) {
|
||||||
|
throw Napi::TypeError::New(env, "First argument must be a string");
|
||||||
|
}
|
||||||
|
if (!info[2].IsBuffer() || (info[2].As<Napi::Buffer<char>>()).Length() != 16) {
|
||||||
|
throw Napi::TypeError::New(env, "Third argument must be a 16 byte Buffer");
|
||||||
|
}
|
||||||
|
const char minor_ver = ToCharVersion(info[0].As<Napi::String>());
|
||||||
|
const int32_t rounds = info[1].As<Napi::Number>();
|
||||||
|
Napi::Buffer<u_int8_t> buffer = info[2].As<Napi::Buffer<u_int8_t>>();
|
||||||
|
u_int8_t* seed = (u_int8_t*) buffer.Data();
|
||||||
|
char salt[_SALT_LEN];
|
||||||
|
bcrypt_gensalt(minor_ver, rounds, seed, salt);
|
||||||
|
return Napi::String::New(env, salt, strlen(salt));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string BufferToString(const Napi::Buffer<char> &buf) {
|
||||||
|
return std::string(buf.Data(), buf.Length());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ENCRYPT DATA - USED TO BE HASHPW */
|
||||||
|
|
||||||
|
class EncryptAsyncWorker : public Napi::AsyncWorker {
|
||||||
|
public:
|
||||||
|
EncryptAsyncWorker(const Napi::Function& callback, const std::string& input, const std::string& salt)
|
||||||
|
: Napi::AsyncWorker(callback, "bcrypt:EncryptAsyncWorker"), input(input), salt(salt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~EncryptAsyncWorker() {}
|
||||||
|
|
||||||
|
void Execute() {
|
||||||
|
if (!(ValidateSalt(salt.c_str()))) {
|
||||||
|
SetError("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
|
||||||
|
}
|
||||||
|
bcrypt(input.c_str(), input.length(), salt.c_str(), bcrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnOK() {
|
||||||
|
Napi::HandleScope scope(Env());
|
||||||
|
Callback().Call({Env().Undefined(),Napi::String::New(Env(), bcrypted)});
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string input;
|
||||||
|
std::string salt;
|
||||||
|
char bcrypted[_PASSWORD_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Value Encrypt(const Napi::CallbackInfo& info) {
|
||||||
|
if (info.Length() < 3) {
|
||||||
|
throw Napi::TypeError::New(info.Env(), "3 arguments expected");
|
||||||
|
}
|
||||||
|
std::string data = info[0].IsBuffer()
|
||||||
|
? BufferToString(info[0].As<Napi::Buffer<char>>())
|
||||||
|
: info[0].As<Napi::String>();
|
||||||
|
std::string salt = info[1].As<Napi::String>();
|
||||||
|
Napi::Function callback = info[2].As<Napi::Function>();
|
||||||
|
EncryptAsyncWorker* encryptWorker = new EncryptAsyncWorker(callback, data, salt);
|
||||||
|
encryptWorker->Queue();
|
||||||
|
return info.Env().Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value EncryptSync(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
if (info.Length() < 2) {
|
||||||
|
throw Napi::TypeError::New(info.Env(), "2 arguments expected");
|
||||||
|
}
|
||||||
|
std::string data = info[0].IsBuffer()
|
||||||
|
? BufferToString(info[0].As<Napi::Buffer<char>>())
|
||||||
|
: info[0].As<Napi::String>();
|
||||||
|
std::string salt = info[1].As<Napi::String>();
|
||||||
|
if (!(ValidateSalt(salt.c_str()))) {
|
||||||
|
throw Napi::Error::New(env, "Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
|
||||||
|
}
|
||||||
|
char bcrypted[_PASSWORD_LEN];
|
||||||
|
bcrypt(data.c_str(), data.length(), salt.c_str(), bcrypted);
|
||||||
|
return Napi::String::New(env, bcrypted, strlen(bcrypted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* COMPARATOR */
|
||||||
|
inline bool CompareStrings(const char* s1, const char* s2) {
|
||||||
|
return strcmp(s1, s2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompareAsyncWorker : public Napi::AsyncWorker {
|
||||||
|
public:
|
||||||
|
CompareAsyncWorker(const Napi::Function& callback, const std::string& input, const std::string& encrypted)
|
||||||
|
: Napi::AsyncWorker(callback, "bcrypt:CompareAsyncWorker"), input(input), encrypted(encrypted) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CompareAsyncWorker() {}
|
||||||
|
|
||||||
|
void Execute() {
|
||||||
|
char bcrypted[_PASSWORD_LEN];
|
||||||
|
if (ValidateSalt(encrypted.c_str())) {
|
||||||
|
bcrypt(input.c_str(), input.length(), encrypted.c_str(), bcrypted);
|
||||||
|
result = CompareStrings(bcrypted, encrypted.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnOK() {
|
||||||
|
Napi::HandleScope scope(Env());
|
||||||
|
Callback().Call({Env().Undefined(), Napi::Boolean::New(Env(), result)});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string input;
|
||||||
|
std::string encrypted;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Value Compare(const Napi::CallbackInfo& info) {
|
||||||
|
if (info.Length() < 3) {
|
||||||
|
throw Napi::TypeError::New(info.Env(), "3 arguments expected");
|
||||||
|
}
|
||||||
|
std::string input = info[0].IsBuffer()
|
||||||
|
? BufferToString(info[0].As<Napi::Buffer<char>>())
|
||||||
|
: info[0].As<Napi::String>();
|
||||||
|
std::string encrypted = info[1].As<Napi::String>();
|
||||||
|
Napi::Function callback = info[2].As<Napi::Function>();
|
||||||
|
CompareAsyncWorker* compareWorker = new CompareAsyncWorker(callback, input, encrypted);
|
||||||
|
compareWorker->Queue();
|
||||||
|
return info.Env().Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value CompareSync(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
if (info.Length() < 2) {
|
||||||
|
throw Napi::TypeError::New(info.Env(), "2 arguments expected");
|
||||||
|
}
|
||||||
|
std::string pw = info[0].IsBuffer()
|
||||||
|
? BufferToString(info[0].As<Napi::Buffer<char>>())
|
||||||
|
: info[0].As<Napi::String>();
|
||||||
|
std::string hash = info[1].As<Napi::String>();
|
||||||
|
char bcrypted[_PASSWORD_LEN];
|
||||||
|
if (ValidateSalt(hash.c_str())) {
|
||||||
|
bcrypt(pw.c_str(), pw.length(), hash.c_str(), bcrypted);
|
||||||
|
return Napi::Boolean::New(env, CompareStrings(bcrypted, hash.c_str()));
|
||||||
|
} else {
|
||||||
|
return Napi::Boolean::New(env, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value GetRounds(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
if (info.Length() < 1) {
|
||||||
|
throw Napi::TypeError::New(env, "1 argument expected");
|
||||||
|
}
|
||||||
|
std::string hash = info[0].As<Napi::String>();
|
||||||
|
u_int32_t rounds;
|
||||||
|
if (!(rounds = bcrypt_get_rounds(hash.c_str()))) {
|
||||||
|
throw Napi::Error::New(env, "invalid hash provided");
|
||||||
|
}
|
||||||
|
return Napi::Number::New(env, rounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||||
|
exports.Set(Napi::String::New(env, "gen_salt_sync"), Napi::Function::New(env, GenerateSaltSync));
|
||||||
|
exports.Set(Napi::String::New(env, "encrypt_sync"), Napi::Function::New(env, EncryptSync));
|
||||||
|
exports.Set(Napi::String::New(env, "compare_sync"), Napi::Function::New(env, CompareSync));
|
||||||
|
exports.Set(Napi::String::New(env, "get_rounds"), Napi::Function::New(env, GetRounds));
|
||||||
|
exports.Set(Napi::String::New(env, "gen_salt"), Napi::Function::New(env, GenerateSalt));
|
||||||
|
exports.Set(Napi::String::New(env, "encrypt"), Napi::Function::New(env, Encrypt));
|
||||||
|
exports.Set(Napi::String::New(env, "compare"), Napi::Function::New(env, Compare));
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_API_MODULE(NODE_GYP_MODULE_NAME, init)
|
||||||
679
node_modules/bcrypt/src/blowfish.cc
generated
vendored
Normal file
679
node_modules/bcrypt/src/blowfish.cc
generated
vendored
Normal file
@ -0,0 +1,679 @@
|
|||||||
|
/* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */
|
||||||
|
/*
|
||||||
|
* Blowfish block cipher for OpenBSD
|
||||||
|
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Implementation advice by David Mazieres <dm@lcs.mit.edu>.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Niels Provos.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is derived from section 14.3 and the given source
|
||||||
|
* in section V of Applied Cryptography, second edition.
|
||||||
|
* Blowfish is an unpatented fast block cipher designed by
|
||||||
|
* Bruce Schneier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "node_blf.h"
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define inline __inline
|
||||||
|
#else /* !__GNUC__ */
|
||||||
|
#define inline
|
||||||
|
#endif /* !__GNUC__ */
|
||||||
|
|
||||||
|
/* Function for Feistel Networks */
|
||||||
|
|
||||||
|
#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \
|
||||||
|
+ (s)[0x100 + (((x)>>16)&0xFF)]) \
|
||||||
|
^ (s)[0x200 + (((x)>> 8)&0xFF)]) \
|
||||||
|
+ (s)[0x300 + ( (x) &0xFF)])
|
||||||
|
|
||||||
|
#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n])
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_encipher(blf_ctx *c, u_int32_t *xl, u_int32_t *xr)
|
||||||
|
{
|
||||||
|
u_int32_t Xl;
|
||||||
|
u_int32_t Xr;
|
||||||
|
u_int32_t *s = c->S[0];
|
||||||
|
u_int32_t *p = c->P;
|
||||||
|
|
||||||
|
Xl = *xl;
|
||||||
|
Xr = *xr;
|
||||||
|
|
||||||
|
Xl ^= p[0];
|
||||||
|
BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2);
|
||||||
|
BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4);
|
||||||
|
BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6);
|
||||||
|
BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8);
|
||||||
|
BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10);
|
||||||
|
BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12);
|
||||||
|
BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14);
|
||||||
|
BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16);
|
||||||
|
|
||||||
|
*xl = Xr ^ p[17];
|
||||||
|
*xr = Xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_decipher(blf_ctx *c, u_int32_t *xl, u_int32_t *xr)
|
||||||
|
{
|
||||||
|
u_int32_t Xl;
|
||||||
|
u_int32_t Xr;
|
||||||
|
u_int32_t *s = c->S[0];
|
||||||
|
u_int32_t *p = c->P;
|
||||||
|
|
||||||
|
Xl = *xl;
|
||||||
|
Xr = *xr;
|
||||||
|
|
||||||
|
Xl ^= p[17];
|
||||||
|
BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15);
|
||||||
|
BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13);
|
||||||
|
BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11);
|
||||||
|
BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9);
|
||||||
|
BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7);
|
||||||
|
BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5);
|
||||||
|
BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3);
|
||||||
|
BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1);
|
||||||
|
|
||||||
|
*xl = Xr ^ p[0];
|
||||||
|
*xr = Xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_initstate(blf_ctx *c)
|
||||||
|
{
|
||||||
|
/* P-box and S-box tables initialized with digits of Pi */
|
||||||
|
|
||||||
|
static const blf_ctx initstate =
|
||||||
|
{ {
|
||||||
|
{
|
||||||
|
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||||
|
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||||
|
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||||
|
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||||
|
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||||
|
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||||
|
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||||
|
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||||
|
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||||
|
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||||
|
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||||
|
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||||
|
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||||
|
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||||
|
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||||
|
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||||
|
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||||
|
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||||
|
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||||
|
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||||
|
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||||
|
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||||
|
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||||
|
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||||
|
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||||
|
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||||
|
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||||
|
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||||
|
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||||
|
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||||
|
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||||
|
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||||
|
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||||
|
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||||
|
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||||
|
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||||
|
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||||
|
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||||
|
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||||
|
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||||
|
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||||
|
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||||
|
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||||
|
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||||
|
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||||
|
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||||
|
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||||
|
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||||
|
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||||
|
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||||
|
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||||
|
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||||
|
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||||
|
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||||
|
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||||
|
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||||
|
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||||
|
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||||
|
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||||
|
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||||
|
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||||
|
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||||
|
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||||
|
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a},
|
||||||
|
{
|
||||||
|
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||||
|
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||||
|
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||||
|
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||||
|
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||||
|
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||||
|
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||||
|
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||||
|
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||||
|
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||||
|
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||||
|
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||||
|
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||||
|
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||||
|
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||||
|
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||||
|
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||||
|
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||||
|
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||||
|
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||||
|
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||||
|
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||||
|
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||||
|
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||||
|
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||||
|
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||||
|
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||||
|
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||||
|
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||||
|
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||||
|
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||||
|
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||||
|
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||||
|
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||||
|
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||||
|
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||||
|
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||||
|
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||||
|
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||||
|
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||||
|
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||||
|
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||||
|
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||||
|
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||||
|
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||||
|
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||||
|
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||||
|
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||||
|
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||||
|
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||||
|
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||||
|
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||||
|
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||||
|
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||||
|
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||||
|
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||||
|
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||||
|
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||||
|
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||||
|
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||||
|
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||||
|
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||||
|
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||||
|
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7},
|
||||||
|
{
|
||||||
|
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||||
|
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||||
|
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||||
|
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||||
|
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||||
|
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||||
|
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||||
|
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||||
|
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||||
|
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||||
|
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||||
|
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||||
|
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||||
|
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||||
|
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||||
|
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||||
|
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||||
|
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||||
|
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||||
|
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||||
|
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||||
|
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||||
|
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||||
|
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||||
|
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||||
|
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||||
|
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||||
|
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||||
|
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||||
|
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||||
|
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||||
|
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||||
|
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||||
|
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||||
|
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||||
|
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||||
|
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||||
|
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||||
|
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||||
|
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||||
|
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||||
|
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||||
|
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||||
|
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||||
|
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||||
|
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||||
|
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||||
|
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||||
|
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||||
|
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||||
|
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||||
|
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||||
|
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||||
|
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||||
|
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||||
|
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||||
|
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||||
|
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||||
|
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||||
|
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||||
|
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||||
|
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||||
|
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||||
|
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0},
|
||||||
|
{
|
||||||
|
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||||
|
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||||
|
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||||
|
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||||
|
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||||
|
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||||
|
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||||
|
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||||
|
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||||
|
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||||
|
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||||
|
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||||
|
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||||
|
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||||
|
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||||
|
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||||
|
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||||
|
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||||
|
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||||
|
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||||
|
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||||
|
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||||
|
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||||
|
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||||
|
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||||
|
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||||
|
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||||
|
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||||
|
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||||
|
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||||
|
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||||
|
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||||
|
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||||
|
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||||
|
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||||
|
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||||
|
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||||
|
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||||
|
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||||
|
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||||
|
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||||
|
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||||
|
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||||
|
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||||
|
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||||
|
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||||
|
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||||
|
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||||
|
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||||
|
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||||
|
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||||
|
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||||
|
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||||
|
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||||
|
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||||
|
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||||
|
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||||
|
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||||
|
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||||
|
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||||
|
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||||
|
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||||
|
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||||
|
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||||
|
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||||
|
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||||
|
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||||
|
0x9216d5d9, 0x8979fb1b
|
||||||
|
} };
|
||||||
|
|
||||||
|
*c = initstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int32_t
|
||||||
|
Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes,
|
||||||
|
u_int16_t *current)
|
||||||
|
{
|
||||||
|
u_int8_t i;
|
||||||
|
u_int16_t j;
|
||||||
|
u_int32_t temp;
|
||||||
|
|
||||||
|
temp = 0x00000000;
|
||||||
|
j = *current;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++, j++) {
|
||||||
|
if (j >= databytes)
|
||||||
|
j = 0;
|
||||||
|
temp = (temp << 8) | data[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
*current = j;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes)
|
||||||
|
{
|
||||||
|
u_int16_t i;
|
||||||
|
u_int16_t j;
|
||||||
|
u_int16_t k;
|
||||||
|
u_int32_t temp;
|
||||||
|
u_int32_t datal;
|
||||||
|
u_int32_t datar;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < BLF_N + 2; i++) {
|
||||||
|
/* Extract 4 int8 to 1 int32 from keystream */
|
||||||
|
temp = Blowfish_stream2word(key, keybytes, &j);
|
||||||
|
c->P[i] = c->P[i] ^ temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
datal = 0x00000000;
|
||||||
|
datar = 0x00000000;
|
||||||
|
for (i = 0; i < BLF_N + 2; i += 2) {
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->P[i] = datal;
|
||||||
|
c->P[i + 1] = datar;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
for (k = 0; k < 256; k += 2) {
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->S[i][k] = datal;
|
||||||
|
c->S[i][k + 1] = datar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes,
|
||||||
|
const u_int8_t *key, u_int16_t keybytes)
|
||||||
|
{
|
||||||
|
u_int16_t i;
|
||||||
|
u_int16_t j;
|
||||||
|
u_int16_t k;
|
||||||
|
u_int32_t temp;
|
||||||
|
u_int32_t datal;
|
||||||
|
u_int32_t datar;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < BLF_N + 2; i++) {
|
||||||
|
/* Extract 4 int8 to 1 int32 from keystream */
|
||||||
|
temp = Blowfish_stream2word(key, keybytes, &j);
|
||||||
|
c->P[i] = c->P[i] ^ temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
datal = 0x00000000;
|
||||||
|
datar = 0x00000000;
|
||||||
|
for (i = 0; i < BLF_N + 2; i += 2) {
|
||||||
|
datal ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
datar ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->P[i] = datal;
|
||||||
|
c->P[i + 1] = datar;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
for (k = 0; k < 256; k += 2) {
|
||||||
|
datal ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
datar ^= Blowfish_stream2word(data, databytes, &j);
|
||||||
|
Blowfish_encipher(c, &datal, &datar);
|
||||||
|
|
||||||
|
c->S[i][k] = datal;
|
||||||
|
c->S[i][k + 1] = datar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len)
|
||||||
|
{
|
||||||
|
/* Initialize S-boxes and subkeys with Pi */
|
||||||
|
Blowfish_initstate(c);
|
||||||
|
|
||||||
|
/* Transform S-boxes and subkeys with key */
|
||||||
|
Blowfish_expand0state(c, k, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
|
||||||
|
{
|
||||||
|
u_int32_t *d;
|
||||||
|
u_int16_t i;
|
||||||
|
|
||||||
|
d = data;
|
||||||
|
for (i = 0; i < blocks; i++) {
|
||||||
|
Blowfish_encipher(c, d, d + 1);
|
||||||
|
d += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
|
||||||
|
{
|
||||||
|
u_int32_t *d;
|
||||||
|
u_int16_t i;
|
||||||
|
|
||||||
|
d = data;
|
||||||
|
for (i = 0; i < blocks; i++) {
|
||||||
|
Blowfish_decipher(c, d, d + 1);
|
||||||
|
d += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
|
||||||
|
{
|
||||||
|
u_int32_t l, r;
|
||||||
|
u_int32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_encipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
|
||||||
|
{
|
||||||
|
u_int32_t l, r;
|
||||||
|
u_int32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len)
|
||||||
|
{
|
||||||
|
u_int32_t l, r;
|
||||||
|
u_int32_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 8) {
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iv[j];
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_encipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
iv = data;
|
||||||
|
data += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len)
|
||||||
|
{
|
||||||
|
u_int32_t l, r;
|
||||||
|
u_int8_t *iv;
|
||||||
|
u_int32_t i, j;
|
||||||
|
|
||||||
|
iv = data + len - 16;
|
||||||
|
data = data + len - 8;
|
||||||
|
for (i = len - 8; i >= 8; i -= 8) {
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iv[j];
|
||||||
|
iv -= 8;
|
||||||
|
data -= 8;
|
||||||
|
}
|
||||||
|
l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||||
|
r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||||
|
Blowfish_decipher(c, &l, &r);
|
||||||
|
data[0] = l >> 24 & 0xff;
|
||||||
|
data[1] = l >> 16 & 0xff;
|
||||||
|
data[2] = l >> 8 & 0xff;
|
||||||
|
data[3] = l & 0xff;
|
||||||
|
data[4] = r >> 24 & 0xff;
|
||||||
|
data[5] = r >> 16 & 0xff;
|
||||||
|
data[6] = r >> 8 & 0xff;
|
||||||
|
data[7] = r & 0xff;
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
data[j] ^= iva[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
report(u_int32_t data[], u_int16_t len)
|
||||||
|
{
|
||||||
|
u_int16_t i;
|
||||||
|
for (i = 0; i < len; i += 2)
|
||||||
|
printf("Block %0hd: %08lx %08lx.\n",
|
||||||
|
i / 2, data[i], data[i + 1]);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
blf_ctx c;
|
||||||
|
char key[] = "AAAAA";
|
||||||
|
char key2[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
u_int32_t data[10];
|
||||||
|
u_int32_t data2[] =
|
||||||
|
{0x424c4f57l, 0x46495348l};
|
||||||
|
|
||||||
|
u_int16_t i;
|
||||||
|
|
||||||
|
/* First test */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
data[i] = i;
|
||||||
|
|
||||||
|
blf_key(&c, (u_int8_t *) key, 5);
|
||||||
|
blf_enc(&c, data, 5);
|
||||||
|
blf_dec(&c, data, 1);
|
||||||
|
blf_dec(&c, data + 2, 4);
|
||||||
|
printf("Should read as 0 - 9.\n");
|
||||||
|
report(data, 10);
|
||||||
|
|
||||||
|
/* Second test */
|
||||||
|
blf_key(&c, (u_int8_t *) key2, strlen(key2));
|
||||||
|
blf_enc(&c, data2, 1);
|
||||||
|
printf("\nShould read as: 0x324ed0fe 0xf413a203.\n");
|
||||||
|
report(data2, 2);
|
||||||
|
blf_dec(&c, data2, 1);
|
||||||
|
report(data2, 2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
132
node_modules/bcrypt/src/node_blf.h
generated
vendored
Normal file
132
node_modules/bcrypt/src/node_blf.h
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
||||||
|
/*
|
||||||
|
* Blowfish - a fast block cipher designed by Bruce Schneier
|
||||||
|
*
|
||||||
|
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Niels Provos.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NODE_BLF_H_
|
||||||
|
#define _NODE_BLF_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* Solaris compatibility */
|
||||||
|
#ifdef __sun
|
||||||
|
#define u_int8_t uint8_t
|
||||||
|
#define u_int16_t uint16_t
|
||||||
|
#define u_int32_t uint32_t
|
||||||
|
#define u_int64_t uint64_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define u_int8_t unsigned __int8
|
||||||
|
#define u_int16_t unsigned __int16
|
||||||
|
#define u_int32_t unsigned __int32
|
||||||
|
#define u_int64_t unsigned __int64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Windows ssize_t compatibility */
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
# if defined(_WIN64)
|
||||||
|
typedef __int64 LONG_PTR;
|
||||||
|
# else
|
||||||
|
typedef long LONG_PTR;
|
||||||
|
# endif
|
||||||
|
typedef LONG_PTR SSIZE_T;
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* z/OS compatibility */
|
||||||
|
#ifdef __MVS__
|
||||||
|
typedef unsigned char u_int8_t;
|
||||||
|
typedef unsigned short u_int16_t;
|
||||||
|
typedef unsigned int u_int32_t;
|
||||||
|
typedef unsigned long long u_int64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BCRYPT_VERSION '2'
|
||||||
|
#define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */
|
||||||
|
#define BCRYPT_BLOCKS 6 /* Ciphertext blocks */
|
||||||
|
#define BCRYPT_MINROUNDS 16 /* we have log2(rounds) in salt */
|
||||||
|
|
||||||
|
/* Schneier specifies a maximum key length of 56 bytes.
|
||||||
|
* This ensures that every key bit affects every cipher
|
||||||
|
* bit. However, the subkeys can hold up to 72 bytes.
|
||||||
|
* Warning: For normal blowfish encryption only 56 bytes
|
||||||
|
* of the key affect all cipherbits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BLF_N 16 /* Number of Subkeys */
|
||||||
|
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
|
||||||
|
#define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */
|
||||||
|
|
||||||
|
#define _PASSWORD_LEN 128 /* max length, not counting NUL */
|
||||||
|
#define _SALT_LEN 32 /* max length */
|
||||||
|
|
||||||
|
/* Blowfish context */
|
||||||
|
typedef struct BlowfishContext {
|
||||||
|
u_int32_t S[4][256]; /* S-Boxes */
|
||||||
|
u_int32_t P[BLF_N + 2]; /* Subkeys */
|
||||||
|
} blf_ctx;
|
||||||
|
|
||||||
|
/* Raw access to customized Blowfish
|
||||||
|
* blf_key is just:
|
||||||
|
* Blowfish_initstate( state )
|
||||||
|
* Blowfish_expand0state( state, key, keylen )
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *);
|
||||||
|
void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *);
|
||||||
|
void Blowfish_initstate(blf_ctx *);
|
||||||
|
void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t);
|
||||||
|
void Blowfish_expandstate
|
||||||
|
(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t);
|
||||||
|
|
||||||
|
/* Standard Blowfish */
|
||||||
|
|
||||||
|
void blf_key(blf_ctx *, const u_int8_t *, u_int16_t);
|
||||||
|
void blf_enc(blf_ctx *, u_int32_t *, u_int16_t);
|
||||||
|
void blf_dec(blf_ctx *, u_int32_t *, u_int16_t);
|
||||||
|
|
||||||
|
void blf_ecb_encrypt(blf_ctx *, u_int8_t *, u_int32_t);
|
||||||
|
void blf_ecb_decrypt(blf_ctx *, u_int8_t *, u_int32_t);
|
||||||
|
|
||||||
|
void blf_cbc_encrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
|
||||||
|
void blf_cbc_decrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
|
||||||
|
|
||||||
|
/* Converts u_int8_t to u_int32_t */
|
||||||
|
u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *);
|
||||||
|
|
||||||
|
/* bcrypt functions*/
|
||||||
|
void bcrypt_gensalt(char, u_int8_t, u_int8_t*, char *);
|
||||||
|
void bcrypt(const char *, size_t key_len, const char *, char *);
|
||||||
|
void encode_salt(char *, u_int8_t *, char, u_int16_t, u_int8_t);
|
||||||
|
u_int32_t bcrypt_get_rounds(const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
209
node_modules/bcrypt/test/async.test.js
generated
vendored
Normal file
209
node_modules/bcrypt/test/async.test.js
generated
vendored
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
|
||||||
|
test('salt_length', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.genSalt(10, function (err, salt) {
|
||||||
|
expect(salt).toHaveLength(29);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_only_cb', () => {
|
||||||
|
expect.assertions(1);
|
||||||
|
expect(() => {
|
||||||
|
bcrypt.genSalt((err, salt) => {
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_string_number', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt('10', void 0, function (err, salt) {
|
||||||
|
expect(err instanceof Error).toBe(true)
|
||||||
|
expect(err.message).toBe('rounds must be a number')
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_string_non_number', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt('z', function (err, salt) {
|
||||||
|
expect(err instanceof Error).toBe(true)
|
||||||
|
expect(err.message).toBe('rounds must be a number')
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_minor', done => {
|
||||||
|
expect.assertions(3);
|
||||||
|
bcrypt.genSalt(10, 'a', function (err, value) {
|
||||||
|
expect(value).toHaveLength(29);
|
||||||
|
const [_, minor, salt] = value.split('$');
|
||||||
|
expect(minor).toEqual('2a');
|
||||||
|
expect(salt).toEqual('10');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_minor_b', done => {
|
||||||
|
expect.assertions(3);
|
||||||
|
bcrypt.genSalt(10, 'b', function (err, value) {
|
||||||
|
expect(value).toHaveLength(29);
|
||||||
|
const [_, minor, salt] = value.split('$');
|
||||||
|
expect(minor).toEqual('2b');
|
||||||
|
expect(salt).toEqual('10');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt(10, function (err, salt) {
|
||||||
|
bcrypt.hash('password', salt, function (err, res) {
|
||||||
|
expect(res).toBeDefined();
|
||||||
|
expect(err).toBeUndefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_rounds', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.hash('bacon', 8, function (err, hash) {
|
||||||
|
expect(bcrypt.getRounds(hash)).toEqual(8);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_empty_strings', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.genSalt(10, function (err, salt) {
|
||||||
|
bcrypt.hash('', salt, function (err, res) {
|
||||||
|
expect(res).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_fails_with_empty_salt', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.hash('', '', function (err, res) {
|
||||||
|
expect(err.message).toBe('Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue')
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_no_params', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.hash(function (err, hash) {
|
||||||
|
expect(err.message).toBe('data must be a string or Buffer and salt must either be a salt string or a number of rounds')
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_one_param', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.hash('password', function (err, hash) {
|
||||||
|
expect(err.message).toBe('data must be a string or Buffer and salt must either be a salt string or a number of rounds');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_salt_validity', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.hash('password', '$2a$10$somesaltyvaluertsetrse', function (err, enc) {
|
||||||
|
expect(err).toBeUndefined();
|
||||||
|
bcrypt.hash('password', 'some$value', function (err, enc) {
|
||||||
|
expect(err.message).toBe("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt(10, function (err, value) {
|
||||||
|
const [_, version, rounds] = value.split('$');
|
||||||
|
expect(version).toEqual('2b');
|
||||||
|
expect(rounds).toEqual('10');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_min_rounds', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt(1, function (err, value) {
|
||||||
|
const [_, version, rounds] = value.split('$');
|
||||||
|
expect(version).toEqual('2b');
|
||||||
|
expect(rounds).toEqual('04');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_max_rounds', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt(100, function (err, value) {
|
||||||
|
const [_, version, rounds] = value.split('$');
|
||||||
|
expect(version).toEqual('2b');
|
||||||
|
expect(rounds).toEqual('31');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
bcrypt.genSalt(10, function (err, salt) {
|
||||||
|
bcrypt.hash("test", salt, function (err, hash) {
|
||||||
|
bcrypt.compare("test", hash, function (err, res) {
|
||||||
|
expect(hash).toBeDefined();
|
||||||
|
bcrypt.compare("blah", hash, function (err, res) {
|
||||||
|
expect(res).toBe(false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_empty_strings', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
const hash = bcrypt.hashSync("test", bcrypt.genSaltSync(10));
|
||||||
|
|
||||||
|
bcrypt.compare("", hash, function (err, res) {
|
||||||
|
expect(res).toEqual(false)
|
||||||
|
bcrypt.compare("", "", function (err, res) {
|
||||||
|
expect(res).toEqual(false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_invalid_strings', done => {
|
||||||
|
expect.assertions(2);
|
||||||
|
const fullString = 'envy1362987212538';
|
||||||
|
const hash = '$2a$10$XOPbrlUPQdwdJUpSrIF6X.LbE14qsMmKGhM1A8W9iqaG3vv1BD7WC';
|
||||||
|
const wut = ':';
|
||||||
|
bcrypt.compare(fullString, hash, function (err, res) {
|
||||||
|
expect(res).toBe(true);
|
||||||
|
bcrypt.compare(fullString, wut, function (err, res) {
|
||||||
|
expect(res).toBe(false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('compare_no_params', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.compare(function (err, hash) {
|
||||||
|
expect(err.message).toBe('data and hash arguments required');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_one_param', done => {
|
||||||
|
expect.assertions(1);
|
||||||
|
bcrypt.compare('password', function (err, hash) {
|
||||||
|
expect(err.message).toBe('data and hash arguments required');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
48
node_modules/bcrypt/test/implementation.test.js
generated
vendored
Normal file
48
node_modules/bcrypt/test/implementation.test.js
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
|
||||||
|
// some tests were adapted from https://github.com/riverrun/bcrypt_elixir/blob/master/test/base_test.exs
|
||||||
|
// which are under the BSD LICENSE
|
||||||
|
|
||||||
|
test('openwall', () => {
|
||||||
|
expect(bcrypt.hashSync("U*U", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW");
|
||||||
|
expect(bcrypt.hashSync("U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK");
|
||||||
|
expect(bcrypt.hashSync("U*U*U", "$2a$05$XXXXXXXXXXXXXXXXXXXXXO")).toStrictEqual("$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a");
|
||||||
|
expect(bcrypt.hashSync("", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy");
|
||||||
|
expect(bcrypt.hashSync("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "$2a$05$abcdefghijklmnopqrstuu")).toStrictEqual("$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui");
|
||||||
|
})
|
||||||
|
|
||||||
|
test('openbsd', () => {
|
||||||
|
expect(bcrypt.hashSync("000000000000000000000000000000000000000000000000000000000000000000000000", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.6.O1dLNbjod2uo0DVcW.jHucKbPDdHS")
|
||||||
|
expect(bcrypt.hashSync("000000000000000000000000000000000000000000000000000000000000000000000000", "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.6.O1dLNbjod2uo0DVcW.jHucKbPDdHS")
|
||||||
|
})
|
||||||
|
|
||||||
|
test('long_passwords', () => {
|
||||||
|
// bcrypt wrap-around bug in $2a$
|
||||||
|
expect(bcrypt.hashSync("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.6.O1dLNbjod2uo0DVcW.jHucKbPDdHS")
|
||||||
|
expect(bcrypt.hashSync("01XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "$2a$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.6.O1dLNbjod2uo0DVcW.jHucKbPDdHS")
|
||||||
|
|
||||||
|
// tests for $2b$ which fixes wrap-around bugs
|
||||||
|
expect(bcrypt.hashSync("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234", "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.XxrQqgBi/5Sxuq9soXzDtjIZ7w5pMfK")
|
||||||
|
expect(bcrypt.hashSync("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345", "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.XxrQqgBi/5Sxuq9soXzDtjIZ7w5pMfK")
|
||||||
|
})
|
||||||
|
|
||||||
|
test('embedded_nulls', () => {
|
||||||
|
expect(bcrypt.hashSync("Passw\0rd123", "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.VHy/kzL4sCcX3Ib3wN5rNGiRt.TpfxS")
|
||||||
|
expect(bcrypt.hashSync("Passw\0 you can literally write anything after the NUL character", "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.4vJLJQ6nZ/70INTjjSZWQ0iyUek92tu")
|
||||||
|
expect(bcrypt.hashSync(Buffer.from("Passw\0 you can literally write anything after the NUL character"), "$2b$05$CCCCCCCCCCCCCCCCCCCCC.")).toStrictEqual("$2b$05$CCCCCCCCCCCCCCCCCCCCC.4vJLJQ6nZ/70INTjjSZWQ0iyUek92tu")
|
||||||
|
})
|
||||||
|
|
||||||
|
test('shorten_salt_to_128_bits', () => {
|
||||||
|
expect(bcrypt.hashSync("test", "$2a$10$1234567899123456789012")).toStrictEqual("$2a$10$123456789912345678901u.OtL1A1eGK5wmvBKUDYKvuVKI7h2XBu")
|
||||||
|
expect(bcrypt.hashSync("U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCCh")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCCeUQ7VjYZ2hd4bLYZdhuPpZMUpEUJDw1S")
|
||||||
|
expect(bcrypt.hashSync("U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCCM")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK")
|
||||||
|
expect(bcrypt.hashSync("U*U*", "$2a$05$CCCCCCCCCCCCCCCCCCCCCA")).toStrictEqual("$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK")
|
||||||
|
})
|
||||||
|
|
||||||
|
test('consistency', () => {
|
||||||
|
expect(bcrypt.hashSync("ππππππππ", "$2a$10$.TtQJ4Jr6isd4Hp.mVfZeu")).toStrictEqual("$2a$10$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle")
|
||||||
|
expect(bcrypt.hashSync("p@5sw0rd", "$2b$12$zQ4CooEXdGqcwi0PHsgc8e")).toStrictEqual("$2b$12$zQ4CooEXdGqcwi0PHsgc8eAf0DLXE/XHoBE8kCSGQ97rXwuClaPam")
|
||||||
|
expect(bcrypt.hashSync("C'est bon, la vie!", "$2b$12$cbo7LZ.wxgW4yxAA5Vqlv.")).toStrictEqual("$2b$12$cbo7LZ.wxgW4yxAA5Vqlv.KR6QFPt4qCdc9RYJNXxa/rbUOp.1sw.")
|
||||||
|
expect(bcrypt.hashSync("ἓν οἶδα ὅτι οὐδὲν οἶδα", "$2b$12$LeHKWR2bmrazi/6P22Jpau")).toStrictEqual("$2b$12$LeHKWR2bmrazi/6P22JpauX5my/eKwwKpWqL7L5iEByBnxNc76FRW")
|
||||||
|
expect(bcrypt.hashSync(Buffer.from("ἓν οἶδα ὅτι οὐδὲν οἶδα"), "$2b$12$LeHKWR2bmrazi/6P22Jpau")).toStrictEqual("$2b$12$LeHKWR2bmrazi/6P22JpauX5my/eKwwKpWqL7L5iEByBnxNc76FRW")
|
||||||
|
})
|
||||||
168
node_modules/bcrypt/test/promise.test.js
generated
vendored
Normal file
168
node_modules/bcrypt/test/promise.test.js
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
const promises = require('../promises');
|
||||||
|
|
||||||
|
test('salt_returns_promise_on_no_args', () => {
|
||||||
|
// make sure test passes with non-native implementations such as bluebird
|
||||||
|
// http://stackoverflow.com/questions/27746304/how-do-i-tell-if-an-object-is-a-promise
|
||||||
|
expect(typeof bcrypt.genSalt().then).toEqual('function')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_returns_promise_on_null_callback', () => {
|
||||||
|
expect(typeof bcrypt.genSalt(13, null, null).then).toEqual('function')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_length', () => {
|
||||||
|
return expect(bcrypt.genSalt(10)).resolves.toHaveLength(29);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_string_number', () => {
|
||||||
|
return expect(bcrypt.genSalt('10')).rejects.toThrow('rounds must be a number');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_string_non_number', () => {
|
||||||
|
return expect(bcrypt.genSalt('b')).rejects.toThrow('rounds must be a number');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_returns_promise_on_null_callback', () => {
|
||||||
|
expect(typeof bcrypt.hash('password', 10, null).then).toStrictEqual('function')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash', () => {
|
||||||
|
return expect(bcrypt.genSalt(10)
|
||||||
|
.then(salt => bcrypt.hash('password', salt))).resolves.toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_rounds', () => {
|
||||||
|
return bcrypt.hash('bacon', 8).then(hash => {
|
||||||
|
expect(bcrypt.getRounds(hash)).toStrictEqual(8)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_empty_strings', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
return Promise.all([
|
||||||
|
expect(bcrypt.genSalt(10)
|
||||||
|
.then(salt => bcrypt.hash('', salt)))
|
||||||
|
.resolves.toBeDefined(),
|
||||||
|
expect(bcrypt.hash('', '')).rejects.toThrow(''),
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_no_params', () => {
|
||||||
|
expect.assertions(1);
|
||||||
|
return expect(bcrypt.hash()).rejects.toThrow('data and salt arguments required');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_one_param', () => {
|
||||||
|
return expect(bcrypt.hash('password')).rejects.toThrow('data and salt arguments required');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_salt_validity', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
return Promise.all(
|
||||||
|
[
|
||||||
|
expect(bcrypt.hash('password', '$2a$10$somesaltyvaluertsetrse')).resolves.toBeDefined(),
|
||||||
|
expect(bcrypt.hash('password', 'some$value')).rejects.toThrow("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue")
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
return bcrypt.genSalt(10).then(result => {
|
||||||
|
const [_, version, salt] = result.split('$');
|
||||||
|
expect(version).toEqual('2b')
|
||||||
|
expect(salt).toEqual('10')
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_min_rounds', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
return bcrypt.genSalt(1).then(value => {
|
||||||
|
const [_, version, rounds] = value.split('$');
|
||||||
|
expect(version).toEqual('2b');
|
||||||
|
expect(rounds).toEqual('04');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_max_rounds', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
return bcrypt.genSalt(100).then(value => {
|
||||||
|
const [_, version, rounds] = value.split('$');
|
||||||
|
expect(version).toEqual('2b');
|
||||||
|
expect(rounds).toEqual('31');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_returns_promise_on_null_callback', () => {
|
||||||
|
expect(typeof bcrypt.compare('password', 'something', null).then).toStrictEqual('function')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare', () => {
|
||||||
|
expect.assertions(3);
|
||||||
|
return bcrypt.genSalt(10).then(function (salt) {
|
||||||
|
expect(salt).toHaveLength(29);
|
||||||
|
return bcrypt.hash("test", salt);
|
||||||
|
}).then(hash => Promise.all(
|
||||||
|
[
|
||||||
|
expect(bcrypt.compare("test", hash)).resolves.toEqual(true),
|
||||||
|
expect(bcrypt.compare("blah", hash)).resolves.toEqual(false)
|
||||||
|
]));
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_empty_strings', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
const hash = bcrypt.hashSync("test", bcrypt.genSaltSync(10));
|
||||||
|
return Promise.all([
|
||||||
|
expect(bcrypt.compare("", hash)).resolves.toEqual(false),
|
||||||
|
expect(bcrypt.compare("", "")).resolves.toEqual(false)
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_invalid_strings', () => {
|
||||||
|
const fullString = 'envy1362987212538';
|
||||||
|
const hash = '$2a$10$XOPbrlUPQdwdJUpSrIF6X.LbE14qsMmKGhM1A8W9iqaG3vv1BD7WC';
|
||||||
|
const wut = ':';
|
||||||
|
return Promise.all([
|
||||||
|
expect(bcrypt.compare(fullString, hash)).resolves.toEqual(true),
|
||||||
|
expect(bcrypt.compare(fullString, wut)).resolves.toEqual(false),
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_no_params', () => {
|
||||||
|
expect.assertions(1);
|
||||||
|
return expect(bcrypt.compare()).rejects.toThrow('data and hash arguments required')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_one_param', () => {
|
||||||
|
expect.assertions(1);
|
||||||
|
return expect(bcrypt.compare('password')).rejects.toThrow('data and hash arguments required')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('change_promise_impl_reject', () => {
|
||||||
|
|
||||||
|
promises.use({
|
||||||
|
reject: function () {
|
||||||
|
return 'mock';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(promises.reject()).toEqual('mock');
|
||||||
|
|
||||||
|
// need to reset the promise implementation because of require cache
|
||||||
|
promises.use(global.Promise);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('change_promise_impl_promise', () => {
|
||||||
|
|
||||||
|
promises.use({
|
||||||
|
reject: function (err) {
|
||||||
|
expect(err.message).toEqual('fn must be a function');
|
||||||
|
return 'mock';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(promises.promise('', '', '')).toEqual('mock');
|
||||||
|
|
||||||
|
// need to reset the promise implementation because of require cache
|
||||||
|
promises.use(global.Promise);
|
||||||
|
})
|
||||||
55
node_modules/bcrypt/test/repetitions.test.js
generated
vendored
Normal file
55
node_modules/bcrypt/test/repetitions.test.js
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
const bcrypt = require('../bcrypt');
|
||||||
|
|
||||||
|
const EXPECTED = 2500; //number of times to iterate these tests.)
|
||||||
|
const { TEST_TIMEOUT_SECONDS } = process.env;
|
||||||
|
let timeout = 5e3; // default test timeout
|
||||||
|
|
||||||
|
// it is necessary to increase the test timeout when emulating cross-architecture
|
||||||
|
// environments (i.e. arm64 from x86-64 host) which have significantly reduced performance:
|
||||||
|
if ( TEST_TIMEOUT_SECONDS )
|
||||||
|
timeout = Number.parseInt(TEST_TIMEOUT_SECONDS, 10) * 1e3;
|
||||||
|
|
||||||
|
jest.setTimeout(timeout);
|
||||||
|
|
||||||
|
test('salt_length', () => {
|
||||||
|
expect.assertions(EXPECTED);
|
||||||
|
|
||||||
|
return Promise.all(Array.from({length: EXPECTED},
|
||||||
|
() => bcrypt.genSalt(10)
|
||||||
|
.then(salt => expect(salt).toHaveLength(29))));
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_hash_length', () => {
|
||||||
|
expect.assertions(EXPECTED);
|
||||||
|
const SALT = '$2a$04$TnjywYklQbbZjdjBgBoA4e';
|
||||||
|
return Promise.all(Array.from({length: EXPECTED},
|
||||||
|
() => bcrypt.hash('test', SALT)
|
||||||
|
.then(hash => expect(hash).toHaveLength(60))));
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_compare', () => {
|
||||||
|
expect.assertions(EXPECTED);
|
||||||
|
const HASH = '$2a$04$TnjywYklQbbZjdjBgBoA4e9G7RJt9blgMgsCvUvus4Iv4TENB5nHy';
|
||||||
|
return Promise.all(Array.from({length: EXPECTED},
|
||||||
|
() => bcrypt.compare('test', HASH)
|
||||||
|
.then(match => expect(match).toEqual(true))));
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_hash_and_compare', () => {
|
||||||
|
expect.assertions(EXPECTED * 3);
|
||||||
|
const salt = bcrypt.genSaltSync(4)
|
||||||
|
|
||||||
|
return Promise.all(Array.from({length: EXPECTED},
|
||||||
|
() => {
|
||||||
|
const password = 'secret' + Math.random();
|
||||||
|
return bcrypt.hash(password, salt)
|
||||||
|
.then(hash => {
|
||||||
|
expect(hash).toHaveLength(60);
|
||||||
|
const goodCompare = bcrypt.compare(password, hash).then(res => expect(res).toEqual(true));
|
||||||
|
const badCompare = bcrypt.compare('bad' + password, hash).then(res => expect(res).toEqual(false));
|
||||||
|
|
||||||
|
return Promise.all([goodCompare, badCompare]);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}, timeout * 3);
|
||||||
|
|
||||||
125
node_modules/bcrypt/test/sync.test.js
generated
vendored
Normal file
125
node_modules/bcrypt/test/sync.test.js
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
const bcrypt = require('../bcrypt')
|
||||||
|
|
||||||
|
test('salt_length', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(13);
|
||||||
|
expect(salt).toHaveLength(29);
|
||||||
|
const [_, version, rounds] = salt.split('$');
|
||||||
|
expect(version).toStrictEqual('2b')
|
||||||
|
expect(rounds).toStrictEqual('13')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_no_params', () => {
|
||||||
|
const salt = bcrypt.genSaltSync();
|
||||||
|
const [_, version, rounds] = salt.split('$');
|
||||||
|
expect(version).toStrictEqual('2b')
|
||||||
|
expect(rounds).toStrictEqual('10')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_string_number', () => {
|
||||||
|
expect(() => bcrypt.genSaltSync('10')).toThrowError('rounds must be a number');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_rounds_is_NaN', () => {
|
||||||
|
expect(() => bcrypt.genSaltSync('b')).toThrowError("rounds must be a number");
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_minor_a', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(10, 'a');
|
||||||
|
const [_, version, rounds] = salt.split('$');
|
||||||
|
expect(version).toStrictEqual('2a')
|
||||||
|
expect(rounds).toStrictEqual('10')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('salt_minor_b', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(10, 'b');
|
||||||
|
const [_, version, rounds] = salt.split('$');
|
||||||
|
expect(version).toStrictEqual('2b')
|
||||||
|
expect(rounds).toStrictEqual('10')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash', () => {
|
||||||
|
expect(() => bcrypt.hashSync('password', bcrypt.genSaltSync(10))).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_rounds', () => {
|
||||||
|
const hash = bcrypt.hashSync('password', 8);
|
||||||
|
expect(bcrypt.getRounds(hash)).toStrictEqual(8)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_empty_string', () => {
|
||||||
|
expect(() => bcrypt.hashSync('', bcrypt.genSaltSync(10))).not.toThrow();
|
||||||
|
expect(() => bcrypt.hashSync('password', '')).toThrowError('Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue');
|
||||||
|
expect(() => bcrypt.hashSync('', '')).toThrowError('Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_pw_no_params', () => {
|
||||||
|
expect(() => bcrypt.hashSync()).toThrow('data and salt arguments required');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_pw_one_param', () => {
|
||||||
|
expect(() => bcrypt.hashSync('password')).toThrow('data and salt arguments required');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_pw_not_hash_str', () => {
|
||||||
|
expect(() => bcrypt.hashSync('password', {})).toThrow("data must be a string or Buffer and salt must either be a salt string or a number of rounds")
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_salt_validity', () => {
|
||||||
|
expect(2);
|
||||||
|
expect(bcrypt.hashSync('password', '$2a$10$somesaltyvaluertsetrse')).toBeDefined()
|
||||||
|
expect(() => bcrypt.hashSync('password', 'some$value')).toThrow('Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(10);
|
||||||
|
const split_salt = salt.split('$');
|
||||||
|
expect(split_salt[1]).toStrictEqual('2b')
|
||||||
|
expect(split_salt[2]).toStrictEqual('10')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_min_rounds', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(1);
|
||||||
|
const split_salt = salt.split('$');
|
||||||
|
expect(split_salt[1]).toStrictEqual('2b')
|
||||||
|
expect(split_salt[2]).toStrictEqual('04')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('verify_salt_max_rounds', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(100);
|
||||||
|
const split_salt = salt.split('$');
|
||||||
|
expect(split_salt[1]).toStrictEqual('2b')
|
||||||
|
expect(split_salt[2]).toStrictEqual('31')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare', () => {
|
||||||
|
const salt = bcrypt.genSaltSync(10);
|
||||||
|
expect(29).toStrictEqual(salt.length)
|
||||||
|
const hash = bcrypt.hashSync("test", salt);
|
||||||
|
expect(bcrypt.compareSync("test", hash)).toBeDefined()
|
||||||
|
expect(!(bcrypt.compareSync("blah", hash))).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_empty_strings', () => {
|
||||||
|
expect(!(bcrypt.compareSync("", "password"))).toBeDefined()
|
||||||
|
expect(!(bcrypt.compareSync("", ""))).toBeDefined()
|
||||||
|
expect(!(bcrypt.compareSync("password", ""))).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hash_compare_invalid_strings', () => {
|
||||||
|
const fullString = 'envy1362987212538';
|
||||||
|
const hash = '$2a$10$XOPbrlUPQdwdJUpSrIF6X.LbE14qsMmKGhM1A8W9iqaG3vv1BD7WC';
|
||||||
|
const wut = ':';
|
||||||
|
expect(bcrypt.compareSync(fullString, hash)).toBe(true);
|
||||||
|
expect(bcrypt.compareSync(fullString, wut)).toBe(false);
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getRounds', () => {
|
||||||
|
const hash = bcrypt.hashSync("test", bcrypt.genSaltSync(9));
|
||||||
|
expect(9).toStrictEqual(bcrypt.getRounds(hash))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getRounds', () => {
|
||||||
|
const hash = bcrypt.hashSync("test", bcrypt.genSaltSync(9));
|
||||||
|
expect(9).toStrictEqual(bcrypt.getRounds(hash))
|
||||||
|
expect(() => bcrypt.getRounds('')).toThrow("invalid hash provided");
|
||||||
|
});
|
||||||
7
node_modules/crypto/README.md
generated
vendored
Normal file
7
node_modules/crypto/README.md
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Deprecated Package
|
||||||
|
|
||||||
|
This package is no longer supported and has been deprecated. To avoid malicious use, npm is hanging on to the package name.
|
||||||
|
|
||||||
|
It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.
|
||||||
|
|
||||||
|
Please contact support@npmjs.com if you have questions about this package.
|
||||||
19
node_modules/crypto/package.json
generated
vendored
Normal file
19
node_modules/crypto/package.json
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "crypto",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/npm/deprecate-holder.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/npm/deprecate-holder/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/npm/deprecate-holder#readme"
|
||||||
|
}
|
||||||
21
node_modules/node-gyp-build/LICENSE
generated
vendored
Normal file
21
node_modules/node-gyp-build/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Mathias Buus
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
58
node_modules/node-gyp-build/README.md
generated
vendored
Normal file
58
node_modules/node-gyp-build/README.md
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# node-gyp-build
|
||||||
|
|
||||||
|
> Build tool and bindings loader for [`node-gyp`][node-gyp] that supports prebuilds.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install node-gyp-build
|
||||||
|
```
|
||||||
|
|
||||||
|
[](https://github.com/prebuild/node-gyp-build/actions/workflows/test.yml)
|
||||||
|
|
||||||
|
Use together with [`prebuildify`][prebuildify] to easily support prebuilds for your native modules.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
> **Note.** Prebuild names have changed in [`prebuildify@3`][prebuildify] and `node-gyp-build@4`. Please see the documentation below.
|
||||||
|
|
||||||
|
`node-gyp-build` works similar to [`node-gyp build`][node-gyp] except that it will check if a build or prebuild is present before rebuilding your project.
|
||||||
|
|
||||||
|
It's main intended use is as an npm install script and bindings loader for native modules that bundle prebuilds using [`prebuildify`][prebuildify].
|
||||||
|
|
||||||
|
First add `node-gyp-build` as an install script to your native project
|
||||||
|
|
||||||
|
``` js
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"scripts": {
|
||||||
|
"install": "node-gyp-build"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your `index.js`, instead of using the [`bindings`](https://www.npmjs.com/package/bindings) module use `node-gyp-build` to load your binding.
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var binding = require('node-gyp-build')(__dirname)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do these two things and bundle prebuilds with [`prebuildify`][prebuildify] your native module will work for most platforms
|
||||||
|
without having to compile on install time AND will work in both node and electron without the need to recompile between usage.
|
||||||
|
|
||||||
|
Users can override `node-gyp-build` and force compiling by doing `npm install --build-from-source`.
|
||||||
|
|
||||||
|
Prebuilds will be attempted loaded from `MODULE_PATH/prebuilds/...` and then next `EXEC_PATH/prebuilds/...` (the latter allowing use with `zeit/pkg`)
|
||||||
|
|
||||||
|
## Supported prebuild names
|
||||||
|
|
||||||
|
If so desired you can bundle more specific flavors, for example `musl` builds to support Alpine, or targeting a numbered ARM architecture version.
|
||||||
|
|
||||||
|
These prebuilds can be bundled in addition to generic prebuilds; `node-gyp-build` will try to find the most specific flavor first. Prebuild filenames are composed of _tags_. The runtime tag takes precedence, as does an `abi` tag over `napi`. For more details on tags, please see [`prebuildify`][prebuildify].
|
||||||
|
|
||||||
|
Values for the `libc` and `armv` tags are auto-detected but can be overridden through the `LIBC` and `ARM_VERSION` environment variables, respectively.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
[prebuildify]: https://github.com/prebuild/prebuildify
|
||||||
|
[node-gyp]: https://www.npmjs.com/package/node-gyp
|
||||||
5
node_modules/node-gyp-build/SECURITY.md
generated
vendored
Normal file
5
node_modules/node-gyp-build/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## Security contact information
|
||||||
|
|
||||||
|
To report a security vulnerability, please use the
|
||||||
|
[Tidelift security contact](https://tidelift.com/security).
|
||||||
|
Tidelift will coordinate the fix and disclosure.
|
||||||
84
node_modules/node-gyp-build/bin.js
generated
vendored
Normal file
84
node_modules/node-gyp-build/bin.js
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
var proc = require('child_process')
|
||||||
|
var os = require('os')
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
|
if (!buildFromSource()) {
|
||||||
|
proc.exec('node-gyp-build-test', function (err, stdout, stderr) {
|
||||||
|
if (err) {
|
||||||
|
if (verbose()) console.error(stderr)
|
||||||
|
preinstall()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
preinstall()
|
||||||
|
}
|
||||||
|
|
||||||
|
function build () {
|
||||||
|
var win32 = os.platform() === 'win32'
|
||||||
|
var shell = win32
|
||||||
|
var args = [win32 ? 'node-gyp.cmd' : 'node-gyp', 'rebuild']
|
||||||
|
|
||||||
|
try {
|
||||||
|
var pkg = require('node-gyp/package.json')
|
||||||
|
args = [
|
||||||
|
process.execPath,
|
||||||
|
path.join(require.resolve('node-gyp/package.json'), '..', typeof pkg.bin === 'string' ? pkg.bin : pkg.bin['node-gyp']),
|
||||||
|
'rebuild'
|
||||||
|
]
|
||||||
|
shell = false
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
proc.spawn(args[0], args.slice(1), { stdio: 'inherit', shell, windowsHide: true }).on('exit', function (code) {
|
||||||
|
if (code || !process.argv[3]) process.exit(code)
|
||||||
|
exec(process.argv[3]).on('exit', function (code) {
|
||||||
|
process.exit(code)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function preinstall () {
|
||||||
|
if (!process.argv[2]) return build()
|
||||||
|
exec(process.argv[2]).on('exit', function (code) {
|
||||||
|
if (code) process.exit(code)
|
||||||
|
build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec (cmd) {
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
var shell = os.platform() === 'android' ? 'sh' : true
|
||||||
|
return proc.spawn(cmd, [], {
|
||||||
|
shell,
|
||||||
|
stdio: 'inherit'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.spawn(cmd, [], {
|
||||||
|
windowsVerbatimArguments: true,
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
windowsHide: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFromSource () {
|
||||||
|
return hasFlag('--build-from-source') || process.env.npm_config_build_from_source === 'true'
|
||||||
|
}
|
||||||
|
|
||||||
|
function verbose () {
|
||||||
|
return hasFlag('--verbose') || process.env.npm_config_loglevel === 'verbose'
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (next major): remove in favor of env.npm_config_* which works since npm
|
||||||
|
// 0.1.8 while npm_config_argv will stop working in npm 7. See npm/rfcs#90
|
||||||
|
function hasFlag (flag) {
|
||||||
|
if (!process.env.npm_config_argv) return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(process.env.npm_config_argv).original.indexOf(flag) !== -1
|
||||||
|
} catch (_) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
19
node_modules/node-gyp-build/build-test.js
generated
vendored
Normal file
19
node_modules/node-gyp-build/build-test.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'test'
|
||||||
|
|
||||||
|
var path = require('path')
|
||||||
|
var test = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
var pkg = require(path.join(process.cwd(), 'package.json'))
|
||||||
|
if (pkg.name && process.env[pkg.name.toUpperCase().replace(/-/g, '_')]) {
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
test = pkg.prebuild.test
|
||||||
|
} catch (err) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test) require(path.join(process.cwd(), test))
|
||||||
|
else require('./')()
|
||||||
6
node_modules/node-gyp-build/index.js
generated
vendored
Normal file
6
node_modules/node-gyp-build/index.js
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // eslint-disable-line
|
||||||
|
if (typeof runtimeRequire.addon === 'function') { // if the platform supports native resolving prefer that
|
||||||
|
module.exports = runtimeRequire.addon.bind(runtimeRequire)
|
||||||
|
} else { // else use the runtime version here
|
||||||
|
module.exports = require('./node-gyp-build.js')
|
||||||
|
}
|
||||||
207
node_modules/node-gyp-build/node-gyp-build.js
generated
vendored
Normal file
207
node_modules/node-gyp-build/node-gyp-build.js
generated
vendored
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
var fs = require('fs')
|
||||||
|
var path = require('path')
|
||||||
|
var os = require('os')
|
||||||
|
|
||||||
|
// Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
|
||||||
|
var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // eslint-disable-line
|
||||||
|
|
||||||
|
var vars = (process.config && process.config.variables) || {}
|
||||||
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY
|
||||||
|
var abi = process.versions.modules // TODO: support old node where this is undef
|
||||||
|
var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node')
|
||||||
|
|
||||||
|
var arch = process.env.npm_config_arch || os.arch()
|
||||||
|
var platform = process.env.npm_config_platform || os.platform()
|
||||||
|
var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc')
|
||||||
|
var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || ''
|
||||||
|
var uv = (process.versions.uv || '').split('.')[0]
|
||||||
|
|
||||||
|
module.exports = load
|
||||||
|
|
||||||
|
function load (dir) {
|
||||||
|
return runtimeRequire(load.resolve(dir))
|
||||||
|
}
|
||||||
|
|
||||||
|
load.resolve = load.path = function (dir) {
|
||||||
|
dir = path.resolve(dir || '.')
|
||||||
|
|
||||||
|
try {
|
||||||
|
var name = runtimeRequire(path.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_')
|
||||||
|
if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD']
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
if (!prebuildsOnly) {
|
||||||
|
var release = getFirst(path.join(dir, 'build/Release'), matchBuild)
|
||||||
|
if (release) return release
|
||||||
|
|
||||||
|
var debug = getFirst(path.join(dir, 'build/Debug'), matchBuild)
|
||||||
|
if (debug) return debug
|
||||||
|
}
|
||||||
|
|
||||||
|
var prebuild = resolve(dir)
|
||||||
|
if (prebuild) return prebuild
|
||||||
|
|
||||||
|
var nearby = resolve(path.dirname(process.execPath))
|
||||||
|
if (nearby) return nearby
|
||||||
|
|
||||||
|
var target = [
|
||||||
|
'platform=' + platform,
|
||||||
|
'arch=' + arch,
|
||||||
|
'runtime=' + runtime,
|
||||||
|
'abi=' + abi,
|
||||||
|
'uv=' + uv,
|
||||||
|
armv ? 'armv=' + armv : '',
|
||||||
|
'libc=' + libc,
|
||||||
|
'node=' + process.versions.node,
|
||||||
|
process.versions.electron ? 'electron=' + process.versions.electron : '',
|
||||||
|
typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line
|
||||||
|
].filter(Boolean).join(' ')
|
||||||
|
|
||||||
|
throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
// Find matching "prebuilds/<platform>-<arch>" directory
|
||||||
|
var tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple)
|
||||||
|
var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0]
|
||||||
|
if (!tuple) return
|
||||||
|
|
||||||
|
// Find most specific flavor first
|
||||||
|
var prebuilds = path.join(dir, 'prebuilds', tuple.name)
|
||||||
|
var parsed = readdirSync(prebuilds).map(parseTags)
|
||||||
|
var candidates = parsed.filter(matchTags(runtime, abi))
|
||||||
|
var winner = candidates.sort(compareTags(runtime))[0]
|
||||||
|
if (winner) return path.join(prebuilds, winner.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readdirSync (dir) {
|
||||||
|
try {
|
||||||
|
return fs.readdirSync(dir)
|
||||||
|
} catch (err) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirst (dir, filter) {
|
||||||
|
var files = readdirSync(dir).filter(filter)
|
||||||
|
return files[0] && path.join(dir, files[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchBuild (name) {
|
||||||
|
return /\.node$/.test(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTuple (name) {
|
||||||
|
// Example: darwin-x64+arm64
|
||||||
|
var arr = name.split('-')
|
||||||
|
if (arr.length !== 2) return
|
||||||
|
|
||||||
|
var platform = arr[0]
|
||||||
|
var architectures = arr[1].split('+')
|
||||||
|
|
||||||
|
if (!platform) return
|
||||||
|
if (!architectures.length) return
|
||||||
|
if (!architectures.every(Boolean)) return
|
||||||
|
|
||||||
|
return { name, platform, architectures }
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchTuple (platform, arch) {
|
||||||
|
return function (tuple) {
|
||||||
|
if (tuple == null) return false
|
||||||
|
if (tuple.platform !== platform) return false
|
||||||
|
return tuple.architectures.includes(arch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTuples (a, b) {
|
||||||
|
// Prefer single-arch prebuilds over multi-arch
|
||||||
|
return a.architectures.length - b.architectures.length
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTags (file) {
|
||||||
|
var arr = file.split('.')
|
||||||
|
var extension = arr.pop()
|
||||||
|
var tags = { file: file, specificity: 0 }
|
||||||
|
|
||||||
|
if (extension !== 'node') return
|
||||||
|
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var tag = arr[i]
|
||||||
|
|
||||||
|
if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
|
||||||
|
tags.runtime = tag
|
||||||
|
} else if (tag === 'napi') {
|
||||||
|
tags.napi = true
|
||||||
|
} else if (tag.slice(0, 3) === 'abi') {
|
||||||
|
tags.abi = tag.slice(3)
|
||||||
|
} else if (tag.slice(0, 2) === 'uv') {
|
||||||
|
tags.uv = tag.slice(2)
|
||||||
|
} else if (tag.slice(0, 4) === 'armv') {
|
||||||
|
tags.armv = tag.slice(4)
|
||||||
|
} else if (tag === 'glibc' || tag === 'musl') {
|
||||||
|
tags.libc = tag
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.specificity++
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchTags (runtime, abi) {
|
||||||
|
return function (tags) {
|
||||||
|
if (tags == null) return false
|
||||||
|
if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
|
||||||
|
if (tags.abi && tags.abi !== abi && !tags.napi) return false
|
||||||
|
if (tags.uv && tags.uv !== uv) return false
|
||||||
|
if (tags.armv && tags.armv !== armv) return false
|
||||||
|
if (tags.libc && tags.libc !== libc) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runtimeAgnostic (tags) {
|
||||||
|
return tags.runtime === 'node' && tags.napi
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTags (runtime) {
|
||||||
|
// Precedence: non-agnostic runtime, abi over napi, then by specificity.
|
||||||
|
return function (a, b) {
|
||||||
|
if (a.runtime !== b.runtime) {
|
||||||
|
return a.runtime === runtime ? -1 : 1
|
||||||
|
} else if (a.abi !== b.abi) {
|
||||||
|
return a.abi ? -1 : 1
|
||||||
|
} else if (a.specificity !== b.specificity) {
|
||||||
|
return a.specificity > b.specificity ? -1 : 1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNwjs () {
|
||||||
|
return !!(process.versions && process.versions.nw)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isElectron () {
|
||||||
|
if (process.versions && process.versions.electron) return true
|
||||||
|
if (process.env.ELECTRON_RUN_AS_NODE) return true
|
||||||
|
return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAlpine (platform) {
|
||||||
|
return platform === 'linux' && fs.existsSync('/etc/alpine-release')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exposed for unit tests
|
||||||
|
// TODO: move to lib
|
||||||
|
load.parseTags = parseTags
|
||||||
|
load.matchTags = matchTags
|
||||||
|
load.compareTags = compareTags
|
||||||
|
load.parseTuple = parseTuple
|
||||||
|
load.matchTuple = matchTuple
|
||||||
|
load.compareTuples = compareTuples
|
||||||
7
node_modules/node-gyp-build/optional.js
generated
vendored
Normal file
7
node_modules/node-gyp-build/optional.js
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/*
|
||||||
|
I am only useful as an install script to make node-gyp not compile for purely optional native deps
|
||||||
|
*/
|
||||||
|
|
||||||
|
process.exit(0)
|
||||||
43
node_modules/node-gyp-build/package.json
generated
vendored
Normal file
43
node_modules/node-gyp-build/package.json
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "node-gyp-build",
|
||||||
|
"version": "4.8.4",
|
||||||
|
"description": "Build tool and bindings loader for node-gyp that supports prebuilds",
|
||||||
|
"main": "index.js",
|
||||||
|
"imports": {
|
||||||
|
"fs": {
|
||||||
|
"bare": "builtin:fs",
|
||||||
|
"default": "fs"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"bare": "builtin:path",
|
||||||
|
"default": "path"
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"bare": "builtin:os",
|
||||||
|
"default": "os"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"array-shuffle": "^1.0.1",
|
||||||
|
"standard": "^14.0.0",
|
||||||
|
"tape": "^5.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "standard && node test"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "./bin.js",
|
||||||
|
"node-gyp-build-optional": "./optional.js",
|
||||||
|
"node-gyp-build-test": "./build-test.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/prebuild/node-gyp-build.git"
|
||||||
|
},
|
||||||
|
"author": "Mathias Buus (@mafintosh)",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/prebuild/node-gyp-build/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/prebuild/node-gyp-build"
|
||||||
|
}
|
||||||
6
node_modules/nodemailer/.gitattributes
generated
vendored
Normal file
6
node_modules/nodemailer/.gitattributes
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
*.js text eol=lf
|
||||||
|
*.txt text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.htm text eol=lf
|
||||||
|
*.ics -text
|
||||||
|
*.bin -text
|
||||||
9
node_modules/nodemailer/.ncurc.js
generated
vendored
Normal file
9
node_modules/nodemailer/.ncurc.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
upgrade: true,
|
||||||
|
reject: [
|
||||||
|
// API changes break existing tests
|
||||||
|
'proxy'
|
||||||
|
]
|
||||||
|
};
|
||||||
8
node_modules/nodemailer/.prettierignore
generated
vendored
Normal file
8
node_modules/nodemailer/.prettierignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
node_modules
|
||||||
|
coverage
|
||||||
|
*.min.js
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
.nyc_output
|
||||||
|
package-lock.json
|
||||||
|
CHANGELOG.md
|
||||||
12
node_modules/nodemailer/.prettierrc
generated
vendored
Normal file
12
node_modules/nodemailer/.prettierrc
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 140,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
10
node_modules/nodemailer/.prettierrc.js
generated
vendored
Normal file
10
node_modules/nodemailer/.prettierrc.js
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 160,
|
||||||
|
tabWidth: 4,
|
||||||
|
singleQuote: true,
|
||||||
|
endOfLine: 'lf',
|
||||||
|
trailingComma: 'none',
|
||||||
|
arrowParens: 'avoid'
|
||||||
|
};
|
||||||
9
node_modules/nodemailer/.release-please-config.json
generated
vendored
Normal file
9
node_modules/nodemailer/.release-please-config.json
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"packages": {
|
||||||
|
".": {
|
||||||
|
"release-type": "node",
|
||||||
|
"package-name": "nodemailer",
|
||||||
|
"pull-request-title-pattern": "chore${scope}: release ${version} [skip-ci]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
966
node_modules/nodemailer/CHANGELOG.md
generated
vendored
Normal file
966
node_modules/nodemailer/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,966 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
## [8.0.2](https://github.com/nodemailer/nodemailer/compare/v8.0.1...v8.0.2) (2026-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* merge fragmented display names with unquoted commas in addressparser ([fe27f7f](https://github.com/nodemailer/nodemailer/commit/fe27f7fd57f7587d897274438da2f628ad0ad7d9))
|
||||||
|
|
||||||
|
## [8.0.1](https://github.com/nodemailer/nodemailer/compare/v8.0.0...v8.0.1) (2026-02-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* absorb TLS errors during socket teardown ([7f8dde4](https://github.com/nodemailer/nodemailer/commit/7f8dde41438c66b8311e888fa5f8c518fcaba6f1))
|
||||||
|
* absorb TLS errors during socket teardown ([381f628](https://github.com/nodemailer/nodemailer/commit/381f628d55e62bb3131bd2a452fa1ce00bc48aea))
|
||||||
|
* Add Gmail Workspace service configuration ([#1787](https://github.com/nodemailer/nodemailer/issues/1787)) ([dc97ede](https://github.com/nodemailer/nodemailer/commit/dc97ede417b3030b311771541b1f17f5ca76bcbf))
|
||||||
|
|
||||||
|
## [8.0.0](https://github.com/nodemailer/nodemailer/compare/v7.0.13...v8.0.0) (2026-02-04)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* Error code 'NoAuth' renamed to 'ENOAUTH'
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add connection fallback to alternative DNS addresses ([e726d6f](https://github.com/nodemailer/nodemailer/commit/e726d6f44aa7ca14e943d4303243cb5494b09c75))
|
||||||
|
* centralize and standardize error codes ([45062ce](https://github.com/nodemailer/nodemailer/commit/45062ce7a4705f3e63c5d9e606547f4d99fd29b5))
|
||||||
|
* harden DNS fallback against race conditions and cleanup issues ([4fa3c63](https://github.com/nodemailer/nodemailer/commit/4fa3c63a1f36aefdbaea7f57a133adc458413a47))
|
||||||
|
* improve socket cleanup to prevent potential memory leaks ([6069fdc](https://github.com/nodemailer/nodemailer/commit/6069fdcff68a3eef9a9bb16b2bf5ddb924c02091))
|
||||||
|
|
||||||
|
## [7.0.13](https://github.com/nodemailer/nodemailer/compare/v7.0.12...v7.0.13) (2026-01-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* downgrade transient connection error logs to warn level ([4c041db](https://github.com/nodemailer/nodemailer/commit/4c041db85d560e98bc5e1fd5d5a191835c5b7d2f))
|
||||||
|
|
||||||
|
## [7.0.12](https://github.com/nodemailer/nodemailer/compare/v7.0.11...v7.0.12) (2025-12-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* added support for REQUIRETLS ([#1793](https://github.com/nodemailer/nodemailer/issues/1793)) ([053ce6a](https://github.com/nodemailer/nodemailer/commit/053ce6a772a7c608e6bee7f58ebe9900afbd9b84))
|
||||||
|
* use 8bit encoding for message/rfc822 attachments ([adf8611](https://github.com/nodemailer/nodemailer/commit/adf86113217b23ff3cd1191af5cd1d360fcc313b))
|
||||||
|
|
||||||
|
## [7.0.11](https://github.com/nodemailer/nodemailer/compare/v7.0.10...v7.0.11) (2025-11-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* prevent stack overflow DoS in addressparser with deeply nested groups ([b61b9c0](https://github.com/nodemailer/nodemailer/commit/b61b9c0cfd682b6f647754ca338373b68336a150))
|
||||||
|
|
||||||
|
## [7.0.10](https://github.com/nodemailer/nodemailer/compare/v7.0.9...v7.0.10) (2025-10-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Increase data URI size limit from 100KB to 50MB and preserve content type ([28dbf3f](https://github.com/nodemailer/nodemailer/commit/28dbf3fe129653f5756c150a98dc40593bfb2cfe))
|
||||||
|
|
||||||
|
## [7.0.9](https://github.com/nodemailer/nodemailer/compare/v7.0.8...v7.0.9) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **release:** Trying to fix release proecess by upgrading Node version in runner ([579fce4](https://github.com/nodemailer/nodemailer/commit/579fce4683eb588891613a6c9a00d8092e8c62d1))
|
||||||
|
|
||||||
|
## [7.0.8](https://github.com/nodemailer/nodemailer/compare/v7.0.7...v7.0.8) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **addressparser:** flatten nested groups per RFC 5322 ([8f8a77c](https://github.com/nodemailer/nodemailer/commit/8f8a77c67f0ba94ddf4e16c68f604a5920fb5d26))
|
||||||
|
|
||||||
|
## [7.0.7](https://github.com/nodemailer/nodemailer/compare/v7.0.6...v7.0.7) (2025-10-05)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **addressparser:** Fixed addressparser handling of quoted nested email addresses ([1150d99](https://github.com/nodemailer/nodemailer/commit/1150d99fba77280df2cfb1885c43df23109a8626))
|
||||||
|
- **dns:** add memory leak prevention for DNS cache ([0240d67](https://github.com/nodemailer/nodemailer/commit/0240d6795ded6d8008d102161a729f120b6d786a))
|
||||||
|
- **linter:** Updated eslint and created prettier formatting task ([df13b74](https://github.com/nodemailer/nodemailer/commit/df13b7487e368acded35e45d0887d23c89c9177a))
|
||||||
|
- refresh expired DNS cache on error ([#1759](https://github.com/nodemailer/nodemailer/issues/1759)) ([ea0fc5a](https://github.com/nodemailer/nodemailer/commit/ea0fc5a6633a3546f4b00fcf2f428e9ca732cdb6))
|
||||||
|
- resolve linter errors in DNS cache tests ([3b8982c](https://github.com/nodemailer/nodemailer/commit/3b8982c1f24508089a8757b74039000a4498b158))
|
||||||
|
|
||||||
|
## [7.0.6](https://github.com/nodemailer/nodemailer/compare/v7.0.5...v7.0.6) (2025-08-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **encoder:** avoid silent data loss by properly flushing trailing base64 ([#1747](https://github.com/nodemailer/nodemailer/issues/1747)) ([01ae76f](https://github.com/nodemailer/nodemailer/commit/01ae76f2cfe991c0c3fe80170f236da60531496b))
|
||||||
|
- handle multiple XOAUTH2 token requests correctly ([#1754](https://github.com/nodemailer/nodemailer/issues/1754)) ([dbe0028](https://github.com/nodemailer/nodemailer/commit/dbe00286351cddf012726a41a96ae613d30a34ee))
|
||||||
|
- ReDoS vulnerability in parseDataURI and \_processDataUrl ([#1755](https://github.com/nodemailer/nodemailer/issues/1755)) ([90b3e24](https://github.com/nodemailer/nodemailer/commit/90b3e24d23929ebf9f4e16261049b40ee4055a39))
|
||||||
|
|
||||||
|
## [7.0.5](https://github.com/nodemailer/nodemailer/compare/v7.0.4...v7.0.5) (2025-07-07)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- updated well known delivery service list ([fa2724b](https://github.com/nodemailer/nodemailer/commit/fa2724b337eb8d8fdcdd788fe903980b061316b8))
|
||||||
|
|
||||||
|
## [7.0.4](https://github.com/nodemailer/nodemailer/compare/v7.0.3...v7.0.4) (2025-06-29)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **pools:** Emit 'clear' once transporter is idle and all connections are closed ([839e286](https://github.com/nodemailer/nodemailer/commit/839e28634c9a93ae4321f399a8c893bf487a09fa))
|
||||||
|
- **smtp-connection:** jsdoc public annotation for socket ([#1741](https://github.com/nodemailer/nodemailer/issues/1741)) ([c45c84f](https://github.com/nodemailer/nodemailer/commit/c45c84fe9b8e2ec5e0615ab02d4197473911ab3e))
|
||||||
|
- **well-known-services:** Added AliyunQiye ([bb9e6da](https://github.com/nodemailer/nodemailer/commit/bb9e6daffb632d7d8f969359859f88a138de3a48))
|
||||||
|
|
||||||
|
## [7.0.3](https://github.com/nodemailer/nodemailer/compare/v7.0.2...v7.0.3) (2025-05-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **attachments:** Set the default transfer encoding for message/rfc822 attachments as '7bit' ([007d5f3](https://github.com/nodemailer/nodemailer/commit/007d5f3f40908c588f1db46c76de8b64ff429327))
|
||||||
|
|
||||||
|
## [7.0.2](https://github.com/nodemailer/nodemailer/compare/v7.0.1...v7.0.2) (2025-05-04)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **ses:** Fixed structured from header ([faa9a5e](https://github.com/nodemailer/nodemailer/commit/faa9a5eafaacbaf85de3540466a04636e12729b3))
|
||||||
|
|
||||||
|
## [7.0.1](https://github.com/nodemailer/nodemailer/compare/v7.0.0...v7.0.1) (2025-05-04)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **ses:** Use formatted FromEmailAddress for SES emails ([821cd09](https://github.com/nodemailer/nodemailer/commit/821cd09002f16c20369cc728b9414c7eb99e4113))
|
||||||
|
|
||||||
|
## [7.0.0](https://github.com/nodemailer/nodemailer/compare/v6.10.1...v7.0.0) (2025-05-03)
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
- SESv2 SDK support, removed older SES SDK v2 and v3 , removed SES rate limiting and idling features
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- SESv2 SDK support, removed older SES SDK v2 and v3 , removed SES rate limiting and idling features ([15db667](https://github.com/nodemailer/nodemailer/commit/15db667af2d0a5ed835281cfdbab16ee73b5edce))
|
||||||
|
|
||||||
|
## [6.10.1](https://github.com/nodemailer/nodemailer/compare/v6.10.0...v6.10.1) (2025-02-06)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- close correct socket ([a18062c](https://github.com/nodemailer/nodemailer/commit/a18062c04d0e05ca4357fbe8f0a59b690fa5391e))
|
||||||
|
|
||||||
|
## [6.10.0](https://github.com/nodemailer/nodemailer/compare/v6.9.16...v6.10.0) (2025-01-23)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **services:** add Seznam email service configuration ([#1695](https://github.com/nodemailer/nodemailer/issues/1695)) ([d1ae0a8](https://github.com/nodemailer/nodemailer/commit/d1ae0a86883ba6011a49a5bbdf076098e2e3637a))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **proxy:** Set error and timeout errors for proxied sockets ([aa0c99c](https://github.com/nodemailer/nodemailer/commit/aa0c99c8f25440bb3dc91f4f3448777c800604d7))
|
||||||
|
|
||||||
|
## [6.9.16](https://github.com/nodemailer/nodemailer/compare/v6.9.15...v6.9.16) (2024-10-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **addressparser:** Correctly detect if user local part is attached to domain part ([f2096c5](https://github.com/nodemailer/nodemailer/commit/f2096c51b92a69ecfbcc15884c28cb2c2f00b826))
|
||||||
|
|
||||||
|
## [6.9.15](https://github.com/nodemailer/nodemailer/compare/v6.9.14...v6.9.15) (2024-08-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Fix memory leak ([#1667](https://github.com/nodemailer/nodemailer/issues/1667)) ([baa28f6](https://github.com/nodemailer/nodemailer/commit/baa28f659641a4bc30360633673d851618f8e8bd))
|
||||||
|
- **mime:** Added GeoJSON closes [#1637](https://github.com/nodemailer/nodemailer/issues/1637) ([#1665](https://github.com/nodemailer/nodemailer/issues/1665)) ([79b8293](https://github.com/nodemailer/nodemailer/commit/79b8293ad557d36f066b4675e649dd80362fd45b))
|
||||||
|
|
||||||
|
## [6.9.14](https://github.com/nodemailer/nodemailer/compare/v6.9.13...v6.9.14) (2024-06-19)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **api:** Added support for Ethereal authentication ([56b2205](https://github.com/nodemailer/nodemailer/commit/56b22052a98de9e363f6c4d26d1512925349c3f3))
|
||||||
|
- **services.json:** Add Email Services Provider Feishu Mail (CN) ([#1648](https://github.com/nodemailer/nodemailer/issues/1648)) ([e9e9ecc](https://github.com/nodemailer/nodemailer/commit/e9e9ecc99b352948a912868c7912b280a05178c6))
|
||||||
|
- **services.json:** update Mailtrap host and port in well known ([#1652](https://github.com/nodemailer/nodemailer/issues/1652)) ([fc2c9ea](https://github.com/nodemailer/nodemailer/commit/fc2c9ea0b4c4f4e514143d2a138c9a23095fc827))
|
||||||
|
- **well-known-services:** Add Loopia in well known services ([#1655](https://github.com/nodemailer/nodemailer/issues/1655)) ([21a28a1](https://github.com/nodemailer/nodemailer/commit/21a28a18fc9fdf8e0e86ddd846e54641395b2cb6))
|
||||||
|
|
||||||
|
## [6.9.13](https://github.com/nodemailer/nodemailer/compare/v6.9.12...v6.9.13) (2024-03-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **tls:** Ensure servername for SMTP ([d66fdd3](https://github.com/nodemailer/nodemailer/commit/d66fdd3dccacc4bc79d697fe9009204cc8d4bde0))
|
||||||
|
|
||||||
|
## [6.9.12](https://github.com/nodemailer/nodemailer/compare/v6.9.11...v6.9.12) (2024-03-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **message-generation:** Escape single quote in address names ([4ae5fad](https://github.com/nodemailer/nodemailer/commit/4ae5fadeaac70ba91abf529fcaae65f829a39101))
|
||||||
|
|
||||||
|
## [6.9.11](https://github.com/nodemailer/nodemailer/compare/v6.9.10...v6.9.11) (2024-02-29)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **headers:** Ensure that Content-type is the bottom header ([c7cf97e](https://github.com/nodemailer/nodemailer/commit/c7cf97e5ecc83f8eee773359951df995c9945446))
|
||||||
|
|
||||||
|
## [6.9.10](https://github.com/nodemailer/nodemailer/compare/v6.9.9...v6.9.10) (2024-02-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **data-uri:** Do not use regular expressions for parsing data URI schemes ([12e65e9](https://github.com/nodemailer/nodemailer/commit/12e65e975d80efe6bafe6de4590829b3b5ebb492))
|
||||||
|
- **data-uri:** Moved all data-uri regexes to use the non-regex parseDataUri method ([edd5dfe](https://github.com/nodemailer/nodemailer/commit/edd5dfe5ce9b725f8b8ae2830797f65b2a2b0a33))
|
||||||
|
|
||||||
|
## [6.9.9](https://github.com/nodemailer/nodemailer/compare/v6.9.8...v6.9.9) (2024-02-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **security:** Fix issues described in GHSA-9h6g-pr28-7cqp. Do not use eternal matching pattern if only a few occurences are expected ([dd8f5e8](https://github.com/nodemailer/nodemailer/commit/dd8f5e8a4ddc99992e31df76bcff9c590035cd4a))
|
||||||
|
- **tests:** Use native node test runner, added code coverage support, removed grunt ([#1604](https://github.com/nodemailer/nodemailer/issues/1604)) ([be45c1b](https://github.com/nodemailer/nodemailer/commit/be45c1b299d012358d69247019391a02734d70af))
|
||||||
|
|
||||||
|
## [6.9.8](https://github.com/nodemailer/nodemailer/compare/v6.9.7...v6.9.8) (2023-12-30)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **punycode:** do not use native punycode module ([b4d0e0c](https://github.com/nodemailer/nodemailer/commit/b4d0e0c7cc4b15bc4d9e287f91d1bcaca87508b0))
|
||||||
|
|
||||||
|
## [6.9.7](https://github.com/nodemailer/nodemailer/compare/v6.9.6...v6.9.7) (2023-10-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **customAuth:** Do not require user and pass to be set for custom authentication schemes (fixes [#1584](https://github.com/nodemailer/nodemailer/issues/1584)) ([41d482c](https://github.com/nodemailer/nodemailer/commit/41d482c3f01e26111b06f3e46351b193db3fb5cb))
|
||||||
|
|
||||||
|
## [6.9.6](https://github.com/nodemailer/nodemailer/compare/v6.9.5...v6.9.6) (2023-10-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **inline:** Use 'inline' as the default Content Dispostion value for embedded images ([db32c93](https://github.com/nodemailer/nodemailer/commit/db32c93fefee527bcc239f13056e5d9181a4d8af))
|
||||||
|
- **tests:** Removed Node v12 from test matrix as it is not compatible with the test framework anymore ([7fe0a60](https://github.com/nodemailer/nodemailer/commit/7fe0a608ed6bcb70dc6b2de543ebfc3a30abf984))
|
||||||
|
|
||||||
|
## [6.9.5](https://github.com/nodemailer/nodemailer/compare/v6.9.4...v6.9.5) (2023-09-06)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- **license:** Updated license year ([da4744e](https://github.com/nodemailer/nodemailer/commit/da4744e491f3a68f4f68e4073684370592630e01))
|
||||||
|
|
||||||
|
## 6.9.4 2023-07-19
|
||||||
|
|
||||||
|
- Renamed SendinBlue to Brevo
|
||||||
|
|
||||||
|
## 6.9.3 2023-05-29
|
||||||
|
|
||||||
|
- Specified license identifier (was defined as MIT, actual value MIT-0)
|
||||||
|
- If SMTP server disconnects with a message, process it and include as part of the response error
|
||||||
|
|
||||||
|
## 6.9.2 2023-05-11
|
||||||
|
|
||||||
|
- Fix uncaught exception on invalid attachment content payload
|
||||||
|
|
||||||
|
## 6.9.1 2023-01-27
|
||||||
|
|
||||||
|
- Fix base64 encoding for emoji bytes in encoded words
|
||||||
|
|
||||||
|
## 6.9.0 2023-01-12
|
||||||
|
|
||||||
|
- Do not throw if failed to resolve IPv4 addresses
|
||||||
|
- Include EHLO extensions in the send response
|
||||||
|
- fix sendMail function: callback should be optional
|
||||||
|
|
||||||
|
## 6.8.0 2022-09-28
|
||||||
|
|
||||||
|
- Add DNS timeout (huksley)
|
||||||
|
- add dns.REFUSED (lucagianfelici)
|
||||||
|
|
||||||
|
## 6.7.8 2022-08-11
|
||||||
|
|
||||||
|
- Allow to use multiple Reply-To addresses
|
||||||
|
|
||||||
|
## 6.7.7 2022-07-06
|
||||||
|
|
||||||
|
- Resolver fixes
|
||||||
|
|
||||||
|
## 6.7.5 2022-05-04
|
||||||
|
|
||||||
|
- No changes, pushing a new README to npmjs.org
|
||||||
|
|
||||||
|
## 6.7.4 2022-04-29
|
||||||
|
|
||||||
|
- Ensure compatibility with Node 18
|
||||||
|
- Replaced Travis with Github Actions
|
||||||
|
|
||||||
|
## 6.7.3 2022-03-21
|
||||||
|
|
||||||
|
- Typo fixes
|
||||||
|
- Added stale issue automation fir Github
|
||||||
|
- Add Infomaniak config to well known service (popod)
|
||||||
|
- Update Outlook/Hotmail host in well known services (popod)
|
||||||
|
- fix: DSN recipient gets ignored (KornKalle)
|
||||||
|
|
||||||
|
## 6.7.2 2021-11-26
|
||||||
|
|
||||||
|
- Fix proxies for account verification
|
||||||
|
|
||||||
|
## 6.7.1 2021-11-15
|
||||||
|
|
||||||
|
- fix verify on ses-transport (stanofsky)
|
||||||
|
|
||||||
|
## 6.7.0 2021-10-11
|
||||||
|
|
||||||
|
- Updated DNS resolving logic. If there are multiple responses for a A/AAAA record, then loop these randomly instead of only caching the first one
|
||||||
|
|
||||||
|
## 6.6.5 2021-09-23
|
||||||
|
|
||||||
|
- Replaced Object.values() and Array.flat() with polyfills to allow using Nodemailer in Node v6+
|
||||||
|
|
||||||
|
## 6.6.4 2021-09-22
|
||||||
|
|
||||||
|
- Better compatibility with IPv6-only SMTP hosts (oxzi)
|
||||||
|
- Fix ses verify for sdk v3 (hannesvdvreken)
|
||||||
|
- Added SECURITY.txt for contact info
|
||||||
|
|
||||||
|
## 6.6.3 2021-07-14
|
||||||
|
|
||||||
|
- Do not show passwords in SMTP transaction logs. All passwords used in logging are replaced by `"/* secret */"`
|
||||||
|
|
||||||
|
## 6.6.1 2021-05-23
|
||||||
|
|
||||||
|
- Fixed address formatting issue where newlines in an email address, if provided via address object, were not properly removed. Reported by tmazeika (#1289)
|
||||||
|
|
||||||
|
## 6.6.0 2021-04-28
|
||||||
|
|
||||||
|
- Added new option `newline` for MailComposer
|
||||||
|
- aws ses connection verification (Ognjen Jevremovic)
|
||||||
|
|
||||||
|
## 6.5.0 2021-02-26
|
||||||
|
|
||||||
|
- Pass through textEncoding to subnodes
|
||||||
|
- Added support for AWS SES v3 SDK
|
||||||
|
- Fixed tests
|
||||||
|
|
||||||
|
## 6.4.18 2021-02-11
|
||||||
|
|
||||||
|
- Updated README
|
||||||
|
|
||||||
|
## 6.4.17 2020-12-11
|
||||||
|
|
||||||
|
- Allow mixing attachments with caendar alternatives
|
||||||
|
|
||||||
|
## 6.4.16 2020-11-12
|
||||||
|
|
||||||
|
- Applied updated prettier formating rules
|
||||||
|
|
||||||
|
## 6.4.15 2020-11-06
|
||||||
|
|
||||||
|
- Minor changes in header key casing
|
||||||
|
|
||||||
|
## 6.4.14 2020-10-14
|
||||||
|
|
||||||
|
- Disabled postinstall script
|
||||||
|
|
||||||
|
## 6.4.13 2020-10-02
|
||||||
|
|
||||||
|
- Fix normalizeHeaderKey method for single node messages
|
||||||
|
|
||||||
|
## 6.4.12 2020-09-30
|
||||||
|
|
||||||
|
- Better handling of attachment filenames that include quote symbols
|
||||||
|
- Includes all information from the oath2 error response in the error message (Normal Gaussian) [1787f227]
|
||||||
|
|
||||||
|
## 6.4.11 2020-07-29
|
||||||
|
|
||||||
|
- Fixed escape sequence handling in address parsing
|
||||||
|
|
||||||
|
## 6.4.10 2020-06-17
|
||||||
|
|
||||||
|
- Fixed RFC822 output for MailComposer when using invalid content-type value. Mostly relevant if message attachments have stragne content-type values set.
|
||||||
|
|
||||||
|
## 6.4.7 2020-05-28
|
||||||
|
|
||||||
|
- Always set charset=utf-8 for Content-Type headers
|
||||||
|
- Catch error when using invalid crypto.sign input
|
||||||
|
|
||||||
|
## 6.4.6 2020-03-20
|
||||||
|
|
||||||
|
- fix: `requeueAttempts=n` should requeue `n` times (Patrick Malouin) [a27ed2f7]
|
||||||
|
|
||||||
|
## 6.4.4 2020-03-01
|
||||||
|
|
||||||
|
- Add `options.forceAuth` for SMTP (Patrick Malouin) [a27ed2f7]
|
||||||
|
|
||||||
|
## 6.4.3 2020-02-22
|
||||||
|
|
||||||
|
- Added an option to specify max number of requeues when connection closes unexpectedly (Igor Sechyn) [8a927f5a]
|
||||||
|
|
||||||
|
## 6.4.2 2019-12-11
|
||||||
|
|
||||||
|
- Fixed bug where array item was used with a potentially empty array
|
||||||
|
|
||||||
|
## 6.4.1 2019-12-07
|
||||||
|
|
||||||
|
- Fix processing server output with unterminated responses
|
||||||
|
|
||||||
|
## 6.4.0 2019-12-04
|
||||||
|
|
||||||
|
- Do not use auth if server does not advertise AUTH support [f419b09d]
|
||||||
|
- add dns.CONNREFUSED (Hiroyuki Okada) [5c4c8ca8]
|
||||||
|
|
||||||
|
## 6.3.1 2019-10-09
|
||||||
|
|
||||||
|
- Ignore "end" events because it might be "error" after it (dex4er) [72bade9]
|
||||||
|
- Set username and password on the connection proxy object correctly (UsamaAshraf) [250b1a8]
|
||||||
|
- Support more DNS errors (madarche) [2391aa4]
|
||||||
|
|
||||||
|
## 6.3.0 2019-07-14
|
||||||
|
|
||||||
|
- Added new option to pass a set of httpHeaders to be sent when fetching attachments. See [PR #1034](https://github.com/nodemailer/nodemailer/pull/1034)
|
||||||
|
|
||||||
|
## 6.2.1 2019-05-24
|
||||||
|
|
||||||
|
- No changes. It is the same as 6.2.0 that was accidentally published as 6.2.1 to npm
|
||||||
|
|
||||||
|
## 6.2.0 2019-05-24
|
||||||
|
|
||||||
|
- Added new option for addressparser: `flatten`. If true then ignores group names and returns a single list of all addresses
|
||||||
|
|
||||||
|
## 6.1.1 2019-04-20
|
||||||
|
|
||||||
|
- Fixed regression bug with missing smtp `authMethod` property
|
||||||
|
|
||||||
|
## 6.1.0 2019-04-06
|
||||||
|
|
||||||
|
- Added new message property `amp` for providing AMP4EMAIL content
|
||||||
|
|
||||||
|
## 6.0.0 2019-03-25
|
||||||
|
|
||||||
|
- SMTPConnection: use removeListener instead of removeAllListeners (xr0master) [ddc4af15]
|
||||||
|
Using removeListener should fix memory leak with Node.js streams
|
||||||
|
|
||||||
|
## 5.1.1 2019-01-09
|
||||||
|
|
||||||
|
- Added missing option argument for custom auth
|
||||||
|
|
||||||
|
## 5.1.0 2019-01-09
|
||||||
|
|
||||||
|
- Official support for custom authentication methods and examples (examples/custom-auth-async.js and examples/custom-auth-cb.js)
|
||||||
|
|
||||||
|
## 5.0.1 2019-01-09
|
||||||
|
|
||||||
|
- Fixed regression error to support Node versions lower than 6.11
|
||||||
|
- Added expiremental custom authentication support
|
||||||
|
|
||||||
|
## 5.0.0 2018-12-28
|
||||||
|
|
||||||
|
- Start using dns.resolve() instead of dns.lookup() for resolving SMTP hostnames. Might be breaking change on some environments so upgrade with care
|
||||||
|
- Show more logs for renewing OAuth2 tokens, previously it was not possible to see what actually failed
|
||||||
|
|
||||||
|
## 4.7.0 2018-11-19
|
||||||
|
|
||||||
|
- Cleaned up List-\* header generation
|
||||||
|
- Fixed 'full' return option for DSN (klaronix) [23b93a3b]
|
||||||
|
- Support promises `for mailcomposer.build()`
|
||||||
|
|
||||||
|
## 4.6.8 2018-08-15
|
||||||
|
|
||||||
|
- Use first IP address from DNS resolution when using a proxy (Limbozz) [d4ca847c]
|
||||||
|
- Return raw email from SES transport (gabegorelick) [3aa08967]
|
||||||
|
|
||||||
|
## 4.6.7 2018-06-15
|
||||||
|
|
||||||
|
- Added option `skipEncoding` to JSONTransport
|
||||||
|
|
||||||
|
## 4.6.6 2018-06-10
|
||||||
|
|
||||||
|
- Fixes mime encoded-word compatibility issue with invalid clients like Zimbra
|
||||||
|
|
||||||
|
## 4.6.5 2018-05-23
|
||||||
|
|
||||||
|
- Fixed broken DKIM stream in Node.js v10
|
||||||
|
- Updated error messages for SMTP responses to not include a newline
|
||||||
|
|
||||||
|
## 4.6.4 2018-03-31
|
||||||
|
|
||||||
|
- Readded logo author link to README that was accidentally removed a while ago
|
||||||
|
|
||||||
|
## 4.6.3 2018-03-13
|
||||||
|
|
||||||
|
- Removed unneeded dependency
|
||||||
|
|
||||||
|
## 4.6.2 2018-03-06
|
||||||
|
|
||||||
|
- When redirecting URL calls then do not include original POST content
|
||||||
|
|
||||||
|
## 4.6.1 2018-03-06
|
||||||
|
|
||||||
|
- Fixed Smtp connection freezing, when trying to send after close / quit (twawszczak) [73d3911c]
|
||||||
|
|
||||||
|
## 4.6.0 2018-02-22
|
||||||
|
|
||||||
|
- Support socks module v2 in addition to v1 [e228bcb2]
|
||||||
|
- Fixed invalid promise return value when using createTestAccount [5524e627]
|
||||||
|
- Allow using local addresses [8f6fa35f]
|
||||||
|
|
||||||
|
## 4.5.0 2018-02-21
|
||||||
|
|
||||||
|
- Added new message transport option `normalizeHeaderKey(key)=>normalizedKey` for custom header formatting
|
||||||
|
|
||||||
|
## 4.4.2 2018-01-20
|
||||||
|
|
||||||
|
- Added sponsors section to README
|
||||||
|
- enclose encodeURIComponent in try..catch to handle invalid urls
|
||||||
|
|
||||||
|
## 4.4.1 2017-12-08
|
||||||
|
|
||||||
|
- Better handling of unexpectedly dropping connections
|
||||||
|
|
||||||
|
## 4.4.0 2017-11-10
|
||||||
|
|
||||||
|
- Changed default behavior for attachment option contentTransferEncoding. If it is unset then base64 encoding is used for the attachment. If it is set to false then previous default applies (base64 for most, 7bit for text)
|
||||||
|
|
||||||
|
## 4.3.1 2017-10-25
|
||||||
|
|
||||||
|
- Fixed a confict with Electron.js where timers do not have unref method
|
||||||
|
|
||||||
|
## 4.3.0 2017-10-23
|
||||||
|
|
||||||
|
- Added new mail object method `mail.normalize(cb)` that should make creating HTTP API based transports much easier
|
||||||
|
|
||||||
|
## 4.2.0 2017-10-13
|
||||||
|
|
||||||
|
- Expose streamed messages size and timers in info response
|
||||||
|
|
||||||
|
## v4.1.3 2017-10-06
|
||||||
|
|
||||||
|
- Allow generating preview links without calling createTestAccount first
|
||||||
|
|
||||||
|
## v4.1.2 2017-10-03
|
||||||
|
|
||||||
|
- No actual changes. Needed to push updated README to npmjs
|
||||||
|
|
||||||
|
## v4.1.1 2017-09-25
|
||||||
|
|
||||||
|
- Fixed JSONTransport attachment handling
|
||||||
|
|
||||||
|
## v4.1.0 2017-08-28
|
||||||
|
|
||||||
|
- Added new methods `createTestAccount` and `getTestMessageUrl` to use autogenerated email accounts from https://Ethereal.email
|
||||||
|
|
||||||
|
## v4.0.1 2017-04-13
|
||||||
|
|
||||||
|
- Fixed issue with LMTP and STARTTLS
|
||||||
|
|
||||||
|
## v4.0.0 2017-04-06
|
||||||
|
|
||||||
|
- License changed from EUPLv1.1 to MIT
|
||||||
|
|
||||||
|
## v3.1.8 2017-03-21
|
||||||
|
|
||||||
|
- Fixed invalid List-\* header generation
|
||||||
|
|
||||||
|
## v3.1.7 2017-03-14
|
||||||
|
|
||||||
|
- Emit an error if STARTTLS ends with connection being closed
|
||||||
|
|
||||||
|
## v3.1.6 2017-03-14
|
||||||
|
|
||||||
|
- Expose last server response for smtpConnection
|
||||||
|
|
||||||
|
## v3.1.5 2017-03-08
|
||||||
|
|
||||||
|
- Fixed SES transport, added missing `response` value
|
||||||
|
|
||||||
|
## v3.1.4 2017-02-26
|
||||||
|
|
||||||
|
- Fixed DKIM calculation for empty body
|
||||||
|
- Ensure linebreak after message content. This fixes DKIM signatures for non-multipart messages where input did not end with a newline
|
||||||
|
|
||||||
|
## v3.1.3 2017-02-17
|
||||||
|
|
||||||
|
- Fixed missing `transport.verify()` methods for SES transport
|
||||||
|
|
||||||
|
## v3.1.2 2017-02-17
|
||||||
|
|
||||||
|
- Added missing error handlers for Sendmail, SES and Stream transports. If a messages contained an invalid URL as attachment then these transports threw an uncatched error
|
||||||
|
|
||||||
|
## v3.1.1 2017-02-13
|
||||||
|
|
||||||
|
- Fixed missing `transport.on('idle')` and `transport.isIdle()` methods for SES transports
|
||||||
|
|
||||||
|
## v3.1.0 2017-02-13
|
||||||
|
|
||||||
|
- Added built-in transport for AWS SES. [Docs](http://localhost:1313/transports/ses/)
|
||||||
|
- Updated stream transport to allow building JSON strings. [Docs](http://localhost:1313/transports/stream/#json-transport)
|
||||||
|
- Added new method _mail.resolveAll_ that fetches all attachments and such to be able to more easily build API-based transports
|
||||||
|
|
||||||
|
## v3.0.2 2017-02-04
|
||||||
|
|
||||||
|
- Fixed a bug with OAuth2 login where error callback was fired twice if getToken was not available.
|
||||||
|
|
||||||
|
## v3.0.1 2017-02-03
|
||||||
|
|
||||||
|
- Fixed a bug where Nodemailer threw an exception if `disableFileAccess` option was used
|
||||||
|
- Added FLOSS [exception declaration](FLOSS_EXCEPTIONS.md)
|
||||||
|
|
||||||
|
## v3.0.0 2017-01-31
|
||||||
|
|
||||||
|
- Initial version of Nodemailer 3
|
||||||
|
|
||||||
|
This update brings a lot of breaking changes:
|
||||||
|
|
||||||
|
- License changed from MIT to **EUPL-1.1**. This was possible as the new version of Nodemailer is a major rewrite. The features I don't have ownership for, were removed or reimplemented. If there's still some snippets in the code that have vague ownership then notify <mailto:andris@kreata.ee> about the conflicting code and I'll fix it.
|
||||||
|
- Requires **Node.js v6+**
|
||||||
|
- All **templating is gone**. It was too confusing to use and to be really universal a huge list of different renderers would be required. Nodemailer is about email, not about parsing different template syntaxes
|
||||||
|
- **No NTLM authentication**. It was too difficult to re-implement. If you still need it then it would be possible to introduce a pluggable SASL interface where you could load the NTLM module in your own code and pass it to Nodemailer. Currently this is not possible.
|
||||||
|
- **OAuth2 authentication** is built in and has a different [configuration](https://nodemailer.com/smtp/oauth2/). You can use both user (3LO) and service (2LO) accounts to generate access tokens from Nodemailer. Additionally there's a new feature to authenticate differently for every message – useful if your application sends on behalf of different users instead of a single sender.
|
||||||
|
- **Improved Calendaring**. Provide an ical file to Nodemailer to send out [calendar events](https://nodemailer.com/message/calendar-events/).
|
||||||
|
|
||||||
|
And also some non-breaking changes:
|
||||||
|
|
||||||
|
- All **dependencies were dropped**. There is exactly 0 dependencies needed to use Nodemailer. This brings the installation time of Nodemailer from NPM down to less than 2 seconds
|
||||||
|
- **Delivery status notifications** added to Nodemailer
|
||||||
|
- Improved and built-in **DKIM** signing of messages. Previously you needed an external module for this and it did quite a lousy job with larger messages
|
||||||
|
- **Stream transport** to return a RFC822 formatted message as a stream. Useful if you want to use Nodemailer as a preprocessor and not for actual delivery.
|
||||||
|
- **Sendmail** transport built-in, no need for external transport plugin
|
||||||
|
|
||||||
|
See [Nodemailer.com](https://nodemailer.com/) for full documentation
|
||||||
|
|
||||||
|
## 2.7.0 2016-12-08
|
||||||
|
|
||||||
|
- Bumped mailcomposer that generates encoded-words differently which might break some tests
|
||||||
|
|
||||||
|
## 2.6.0 2016-09-05
|
||||||
|
|
||||||
|
- Added new options disableFileAccess and disableUrlAccess
|
||||||
|
- Fixed envelope handling where cc/bcc fields were ignored in the envelope object
|
||||||
|
|
||||||
|
## 2.4.2 2016-05-25
|
||||||
|
|
||||||
|
- Removed shrinkwrap file. Seemed to cause more trouble than help
|
||||||
|
|
||||||
|
## 2.4.1 2016-05-12
|
||||||
|
|
||||||
|
- Fixed outdated shrinkwrap file
|
||||||
|
|
||||||
|
## 2.4.0 2016-05-11
|
||||||
|
|
||||||
|
- Bumped mailcomposer module to allow using `false` as attachment filename (suppresses filename usage)
|
||||||
|
- Added NTLM authentication support
|
||||||
|
|
||||||
|
## 2.3.2 2016-04-11
|
||||||
|
|
||||||
|
- Bumped smtp transport modules to get newest smtp-connection that fixes SMTPUTF8 support for internationalized email addresses
|
||||||
|
|
||||||
|
## 2.3.1 2016-04-08
|
||||||
|
|
||||||
|
- Bumped mailcomposer to have better support for message/822 attachments
|
||||||
|
|
||||||
|
## 2.3.0 2016-03-03
|
||||||
|
|
||||||
|
- Fixed a bug with attachment filename that contains mixed unicode and dashes
|
||||||
|
- Added built-in support for proxies by providing a new SMTP option `proxy` that takes a proxy configuration url as its value
|
||||||
|
- Added option `transport` to dynamically load transport plugins
|
||||||
|
- Do not require globally installed grunt-cli
|
||||||
|
|
||||||
|
## 2.2.1 2016-02-20
|
||||||
|
|
||||||
|
- Fixed a bug in SMTP requireTLS option that was broken
|
||||||
|
|
||||||
|
## 2.2.0 2016-02-18
|
||||||
|
|
||||||
|
- Removed the need to use `clone` dependency
|
||||||
|
- Added new method `verify` to check SMTP configuration
|
||||||
|
- Direct transport uses STARTTLS by default, fallbacks to plaintext if STARTTLS fails
|
||||||
|
- Added new message option `list` for setting List-\* headers
|
||||||
|
- Add simple proxy support with `getSocket` method
|
||||||
|
- Added new message option `textEncoding`. If `textEncoding` is not set then detect best encoding automatically
|
||||||
|
- Added new message option `icalEvent` to embed iCalendar events. Example [here](examples/ical-event.js)
|
||||||
|
- Added new attachment option `raw` to use prepared MIME contents instead of generating a new one. This might be useful when you want to handcraft some parts of the message yourself, for example if you want to inject a PGP encrypted message as the contents of a MIME node
|
||||||
|
- Added new message option `raw` to use an existing MIME message instead of generating a new one
|
||||||
|
|
||||||
|
## 2.1.0 2016-02-01
|
||||||
|
|
||||||
|
Republishing 2.1.0-rc.1 as stable. To recap, here's the notable changes between v2.0 and v2.1:
|
||||||
|
|
||||||
|
- Implemented templating support. You can either use a simple built-in renderer or some external advanced renderer, eg. [node-email-templates](https://github.com/niftylettuce/node-email-templates). Templating [docs](http://nodemailer.com/2-0-0-beta/templating/).
|
||||||
|
- Updated smtp-pool to emit 'idle' events in order to handle message queue more effectively
|
||||||
|
- Updated custom header handling, works everywhere the same now, no differences between adding custom headers to the message or to an attachment
|
||||||
|
|
||||||
|
## 2.1.0-rc.1 2016-01-25
|
||||||
|
|
||||||
|
Sneaked in some new features even though it is already rc
|
||||||
|
|
||||||
|
- If a SMTP pool is closed while there are still messages in a queue, the message callbacks are invoked with an error
|
||||||
|
- In case of SMTP pool the transporter emits 'idle' when there is a free connection slot available
|
||||||
|
- Added method `isIdle()` that checks if a pool has still some free connection slots available
|
||||||
|
|
||||||
|
## 2.1.0-rc.0 2016-01-20
|
||||||
|
|
||||||
|
- Bumped dependency versions
|
||||||
|
|
||||||
|
## 2.1.0-beta.3 2016-01-20
|
||||||
|
|
||||||
|
- Added support for node-email-templates templating in addition to the built-in renderer
|
||||||
|
|
||||||
|
## 2.1.0-beta.2 2016-01-20
|
||||||
|
|
||||||
|
- Implemented simple templating feature
|
||||||
|
|
||||||
|
## 2.1.0-beta.1 2016-01-20
|
||||||
|
|
||||||
|
- Allow using prepared header values that are not folded or encoded by Nodemailer
|
||||||
|
|
||||||
|
## 2.1.0-beta.0 2016-01-20
|
||||||
|
|
||||||
|
- Use the same header custom structure for message root, attachments and alternatives
|
||||||
|
- Ensure that Message-Id exists when accessing message
|
||||||
|
- Allow using array values for custom headers (inserts every value in its own row)
|
||||||
|
|
||||||
|
## 2.0.0 2016-01-11
|
||||||
|
|
||||||
|
- Released rc.2 as stable
|
||||||
|
|
||||||
|
## 2.0.0-rc.2 2016-01-04
|
||||||
|
|
||||||
|
- Locked dependencies
|
||||||
|
|
||||||
|
## 2.0.0-beta.2 2016-01-04
|
||||||
|
|
||||||
|
- Updated documentation to reflect changes with SMTP handling
|
||||||
|
- Use beta versions for smtp/pool/direct transports
|
||||||
|
- Updated logging
|
||||||
|
|
||||||
|
## 2.0.0-beta.1 2016-01-03
|
||||||
|
|
||||||
|
- Use bunyan compatible logger instead of the emit('log') style
|
||||||
|
- Outsourced some reusable methods to nodemailer-shared
|
||||||
|
- Support setting direct/smtp/pool with the default configuration
|
||||||
|
|
||||||
|
## 2.0.0-beta.0 2015-12-31
|
||||||
|
|
||||||
|
- Stream errors are not silently swallowed
|
||||||
|
- Do not use format=flowed
|
||||||
|
- Use nodemailer-fetch to fetch URL streams
|
||||||
|
- jshint replaced by eslint
|
||||||
|
|
||||||
|
## v1.11.0 2015-12-28
|
||||||
|
|
||||||
|
Allow connection url based SMTP configurations
|
||||||
|
|
||||||
|
## v1.10.0 2015-11-13
|
||||||
|
|
||||||
|
Added `defaults` argument for `createTransport` to predefine commonn values (eg. `from` address)
|
||||||
|
|
||||||
|
## v1.9.0 2015-11-09
|
||||||
|
|
||||||
|
Returns a Promise for `sendMail` if callback is not defined
|
||||||
|
|
||||||
|
## v1.8.0 2015-10-08
|
||||||
|
|
||||||
|
Added priority option (high, normal, low) for setting Importance header
|
||||||
|
|
||||||
|
## v1.7.0 2015-10-06
|
||||||
|
|
||||||
|
Replaced hyperquest with needle. Fixes issues with compressed data and redirects
|
||||||
|
|
||||||
|
## v1.6.0 2015-10-05
|
||||||
|
|
||||||
|
Maintenance release. Bumped dependencies to get support for unicode filenames for QQ webmail and to support emoji in filenames
|
||||||
|
|
||||||
|
## v1.5.0 2015-09-24
|
||||||
|
|
||||||
|
Use mailcomposer instead of built in solution to generate message sources. Bumped libmime gives better quoted-printable handling.
|
||||||
|
|
||||||
|
## v1.4.0 2015-06-27
|
||||||
|
|
||||||
|
Added new message option `watchHtml` to specify Apple Watch specific HTML part of the message. See [this post](https://litmus.com/blog/how-to-send-hidden-version-email-apple-watch) for details
|
||||||
|
|
||||||
|
## v1.3.4 2015-04-25
|
||||||
|
|
||||||
|
Maintenance release, bumped buildmail version to get fixed format=flowed handling
|
||||||
|
|
||||||
|
## v1.3.3 2015-04-25
|
||||||
|
|
||||||
|
Maintenance release, bumped dependencies
|
||||||
|
|
||||||
|
## v1.3.2 2015-03-09
|
||||||
|
|
||||||
|
Maintenance release, upgraded dependencies. Replaced simplesmtp based tests with smtp-server based ones.
|
||||||
|
|
||||||
|
## v1.3.0 2014-09-12
|
||||||
|
|
||||||
|
Maintenance release, upgrades buildmail and libmime. Allows using functions as transform plugins and fixes issue with unicode filenames in Gmail.
|
||||||
|
|
||||||
|
## v1.2.2 2014-09-05
|
||||||
|
|
||||||
|
Proper handling of data uris as attachments. Attachment `path` property can also be defined as a data uri, not just regular url or file path.
|
||||||
|
|
||||||
|
## v1.2.1 2014-08-21
|
||||||
|
|
||||||
|
Bumped libmime and mailbuild versions to properly handle filenames with spaces (short ascii only filenames with spaces were left unquoted).
|
||||||
|
|
||||||
|
## v1.2.0 2014-08-18
|
||||||
|
|
||||||
|
Allow using encoded strings as attachments. Added new property `encoding` which defines the encoding used for a `content` string. If encoding is set, the content value is converted to a Buffer value using the defined encoding before usage. Useful for including binary attachemnts in JSON formatted email objects.
|
||||||
|
|
||||||
|
## v1.1.2 2014-08-18
|
||||||
|
|
||||||
|
Return deprecatin error for v0.x style configuration
|
||||||
|
|
||||||
|
## v1.1.1 2014-07-30
|
||||||
|
|
||||||
|
Bumped nodemailer-direct-transport dependency. Updated version includes a bugfix for Stream nodes handling. Important only if use direct-transport with Streams (not file paths or urls) as attachment content.
|
||||||
|
|
||||||
|
## v1.1.0 2014-07-29
|
||||||
|
|
||||||
|
Added new method `resolveContent()` to get the html/text/attachment content as a String or Buffer.
|
||||||
|
|
||||||
|
## v1.0.4 2014-07-23
|
||||||
|
|
||||||
|
Bugfix release. HTML node was instered twice if the message consisted of a HTML content (but no text content) + at least one attachment with CID + at least one attachment without CID. In this case the HTML node was inserted both to the root level multipart/mixed section and to the multipart/related sub section
|
||||||
|
|
||||||
|
## v1.0.3 2014-07-16
|
||||||
|
|
||||||
|
Fixed a bug where Nodemailer crashed if the message content type was multipart/related
|
||||||
|
|
||||||
|
## v1.0.2 2014-07-16
|
||||||
|
|
||||||
|
Upgraded nodemailer-smtp-transport to 0.1.11\. The docs state that for SSL you should use 'secure' option but the underlying smtp-connection module used 'secureConnection' for this purpose. Fixed smpt-connection to match the docs.
|
||||||
|
|
||||||
|
## v1.0.1 2014-07-15
|
||||||
|
|
||||||
|
Implemented missing #close method that is passed to the underlying transport object. Required by the smtp pool.
|
||||||
|
|
||||||
|
## v1.0.0 2014-07-15
|
||||||
|
|
||||||
|
Total rewrite. See migration guide here: <http://www.andrisreinman.com/nodemailer-v1-0/#migrationguide>
|
||||||
|
|
||||||
|
## v0.7.1 2014-07-09
|
||||||
|
|
||||||
|
- Upgraded aws-sdk to 2.0.5
|
||||||
|
|
||||||
|
## v0.7.0 2014-06-17
|
||||||
|
|
||||||
|
- Bumped version to v0.7.0
|
||||||
|
- Fix AWS-SES usage [5b6bc144]
|
||||||
|
- Replace current SES with new SES using AWS-SDK (Elanorr) [c79d797a]
|
||||||
|
- Updated README.md about Node Email Templates (niftylettuce) [e52bef81]
|
||||||
|
|
||||||
|
## v0.6.5 2014-05-15
|
||||||
|
|
||||||
|
- Bumped version to v0.6.5
|
||||||
|
- Use tildes instead of carets for dependency listing [5296ce41]
|
||||||
|
- Allow clients to set a custom identityString (venables) [5373287d]
|
||||||
|
- bugfix (adding "-i" to sendmail command line for each new mail) by copying this.args (vrodic) [05a8a9a3]
|
||||||
|
- update copyright (gdi2290) [3a6cba3a]
|
||||||
|
|
||||||
|
## v0.6.4 2014-05-13
|
||||||
|
|
||||||
|
- Bumped version to v0.6.4
|
||||||
|
- added npmignore, bumped dependencies [21bddcd9]
|
||||||
|
- Add AOL to well-known services (msouce) [da7dd3b7]
|
||||||
|
|
||||||
|
## v0.6.3 2014-04-16
|
||||||
|
|
||||||
|
- Bumped version to v0.6.3
|
||||||
|
- Upgraded simplesmtp dependency [dd367f59]
|
||||||
|
|
||||||
|
## v0.6.2 2014-04-09
|
||||||
|
|
||||||
|
- Bumped version to v0.6.2
|
||||||
|
- Added error option to Stub transport [c423acad]
|
||||||
|
- Use SVG npm badge (t3chnoboy) [677117b7]
|
||||||
|
- add SendCloud to well known services (haio) [43c358e0]
|
||||||
|
- High-res build-passing and NPM module badges (sahat) [9fdc37cd]
|
||||||
|
|
||||||
|
## v0.6.1 2014-01-26
|
||||||
|
|
||||||
|
- Bumped version to v0.6.1
|
||||||
|
- Do not throw on multiple errors from sendmail command [c6e2cd12]
|
||||||
|
- Do not require callback for pickup, fixes #238 [93eb3214]
|
||||||
|
- Added AWSSecurityToken information to README, fixes #235 [58e921d1]
|
||||||
|
- Added Nodemailer logo [06b7d1a8]
|
||||||
|
|
||||||
|
## v0.6.0 2013-12-30
|
||||||
|
|
||||||
|
- Bumped version to v0.6.0
|
||||||
|
- Allow defining custom transport methods [ec5b48ce]
|
||||||
|
- Return messageId with responseObject for all built in transport methods [74445cec]
|
||||||
|
- Bumped dependency versions for mailcomposer and readable-stream [9a034c34]
|
||||||
|
- Changed pickup argument name to 'directory' [01c3ea53]
|
||||||
|
- Added support for IIS pickup directory with PICKUP transport (philipproplesch) [36940b59..360a2878]
|
||||||
|
- Applied common styles [9e93a409]
|
||||||
|
- Updated readme [c78075e7]
|
||||||
|
|
||||||
|
## v0.5.15 2013-12-13
|
||||||
|
|
||||||
|
- bumped version to v0.5.15
|
||||||
|
- Updated README, added global options info for setting uo transports [554bb0e5]
|
||||||
|
- Resolve public hostname, if resolveHostname property for a transport object is set to `true` [9023a6e1..4c66b819]
|
||||||
|
|
||||||
|
## v0.5.14 2013-12-05
|
||||||
|
|
||||||
|
- bumped version to v0.5.14
|
||||||
|
- Expose status for direct messages [f0312df6]
|
||||||
|
- Allow to skip the X-Mailer header if xMailer value is set to 'false' [f2c20a68]
|
||||||
|
|
||||||
|
## v0.5.13 2013-12-03
|
||||||
|
|
||||||
|
- bumped version to v0.5.13
|
||||||
|
- Use the name property from the transport object to use for the domain part of message-id values (1598eee9)
|
||||||
|
|
||||||
|
## v0.5.12 2013-12-02
|
||||||
|
|
||||||
|
- bumped version to v0.5.12
|
||||||
|
- Expose transport method and transport module version if available [a495106e]
|
||||||
|
- Added 'he' module instead of using custom html entity decoding [c197d102]
|
||||||
|
- Added xMailer property for transport configuration object to override X-Mailer value [e8733a61]
|
||||||
|
- Updated README, added description for 'mail' method [e1f5f3a6]
|
||||||
|
|
||||||
|
## v0.5.11 2013-11-28
|
||||||
|
|
||||||
|
- bumped version to v0.5.11
|
||||||
|
- Updated mailcomposer version. Replaces ent with he [6a45b790e]
|
||||||
|
|
||||||
|
## v0.5.10 2013-11-26
|
||||||
|
|
||||||
|
- bumped version to v0.5.10
|
||||||
|
- added shorthand function mail() for direct transport type [88129bd7]
|
||||||
|
- minor tweaks and typo fixes [f797409e..ceac0ca4]
|
||||||
|
|
||||||
|
## v0.5.9 2013-11-25
|
||||||
|
|
||||||
|
- bumped version to v0.5.9
|
||||||
|
- Update for 'direct' handling [77b84e2f]
|
||||||
|
- do not require callback to be provided for 'direct' type [ec51c79f]
|
||||||
|
|
||||||
|
## v0.5.8 2013-11-22
|
||||||
|
|
||||||
|
- bumped version to v0.5.8
|
||||||
|
- Added support for 'direct' transport [826f226d..0dbbcbbc]
|
||||||
|
|
||||||
|
## v0.5.7 2013-11-18
|
||||||
|
|
||||||
|
- bumped version to v0.5.7
|
||||||
|
- Replace \r\n by \n in Sendmail transport (rolftimmermans) [fed2089e..616ec90c] A lot of sendmail implementations choke on \r\n newlines and require \n This commit addresses this by transforming all \r\n sequences passed to the sendmail command with \n
|
||||||
|
|
||||||
|
## v0.5.6 2013-11-15
|
||||||
|
|
||||||
|
- bumped version to v0.5.6
|
||||||
|
- Upgraded mailcomposer dependency to 0.2.4 [e5ff9c40]
|
||||||
|
- Removed noCR option [e810d1b8]
|
||||||
|
- Update wellknown.js, added FastMail (k-j-kleist) [cf930f6d]
|
||||||
|
|
||||||
|
## v0.5.5 2013-10-30
|
||||||
|
|
||||||
|
- bumped version to v0.5.5
|
||||||
|
- Updated mailcomposer dependnecy version to 0.2.3
|
||||||
|
- Remove legacy code - node v0.4 is not supported anymore anyway
|
||||||
|
- Use hostname (autodetected or from the options.name property) for Message-Id instead of "Nodemailer" (helps a bit when messages are identified as spam)
|
||||||
|
- Added maxMessages info to README
|
||||||
|
|
||||||
|
## v0.5.4 2013-10-29
|
||||||
|
|
||||||
|
- bumped version to v0.5.4
|
||||||
|
- added "use strict" statements
|
||||||
|
- Added DSN info to README
|
||||||
|
- add support for QQ enterprise email (coderhaoxin)
|
||||||
|
- Add a Bitdeli Badge to README
|
||||||
|
- DSN options Passthrought into simplesmtp. (irvinzz)
|
||||||
|
|
||||||
|
## v0.5.3 2013-10-03
|
||||||
|
|
||||||
|
- bumped version v0.5.3
|
||||||
|
- Using a stub transport to prevent sendmail from being called during a test. (jsdevel)
|
||||||
|
- closes #78: sendmail transport does not work correctly on Unix machines. (jsdevel)
|
||||||
|
- Updated PaaS Support list to include Modulus. (fiveisprime)
|
||||||
|
- Translate self closing break tags to newline (kosmasgiannis)
|
||||||
|
- fix typos (aeosynth)
|
||||||
|
|
||||||
|
## v0.5.2 2013-07-25
|
||||||
|
|
||||||
|
- bumped version v0.5.2
|
||||||
|
- Merge pull request #177 from MrSwitch/master Fixing Amazon SES, fatal error caused by bad connection
|
||||||
76
node_modules/nodemailer/CODE_OF_CONDUCT.md
generated
vendored
Normal file
76
node_modules/nodemailer/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||||
|
level of experience, education, socio-economic status, nationality, personal
|
||||||
|
appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
- Using welcoming and inclusive language
|
||||||
|
- Being respectful of differing viewpoints and experiences
|
||||||
|
- Gracefully accepting constructive criticism
|
||||||
|
- Focusing on what is best for the community
|
||||||
|
- Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
- Public or private harassment
|
||||||
|
- Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
- Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at info@nodemailer.com. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see
|
||||||
|
https://www.contributor-covenant.org/faq
|
||||||
16
node_modules/nodemailer/LICENSE
generated
vendored
Normal file
16
node_modules/nodemailer/LICENSE
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Copyright (c) 2011-2023 Andris Reinman
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
86
node_modules/nodemailer/README.md
generated
vendored
Normal file
86
node_modules/nodemailer/README.md
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# Nodemailer
|
||||||
|
|
||||||
|
[](https://nodemailer.com/about/)
|
||||||
|
|
||||||
|
Send emails from Node.js – easy as cake! 🍰✉️
|
||||||
|
|
||||||
|
[](https://nodemailer.com/about/)
|
||||||
|
|
||||||
|
See [nodemailer.com](https://nodemailer.com/) for documentation and terms.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Check out **[EmailEngine](https://emailengine.app/?utm_source=github-nodemailer&utm_campaign=nodemailer&utm_medium=readme-link)** – a self-hosted email gateway that allows making **REST requests against IMAP and SMTP servers**. EmailEngine also sends webhooks whenever something changes on the registered accounts.\
|
||||||
|
> \
|
||||||
|
> Using the email accounts registered with EmailEngine, you can receive and [send emails](https://emailengine.app/sending-emails?utm_source=github-nodemailer&utm_campaign=nodemailer&utm_medium=readme-link). EmailEngine supports OAuth2, delayed sends, opens and clicks tracking, bounce detection, etc. All on top of regular email accounts without an external MTA service.
|
||||||
|
|
||||||
|
## Having an issue?
|
||||||
|
|
||||||
|
#### First review the docs
|
||||||
|
|
||||||
|
Documentation for Nodemailer can be found at [nodemailer.com](https://nodemailer.com/about/).
|
||||||
|
|
||||||
|
#### Nodemailer throws a SyntaxError for "..."
|
||||||
|
|
||||||
|
You are using an older Node.js version than v6.0. Upgrade Node.js to get support for the spread operator. Nodemailer supports all Node.js versions starting from Node.js@v6.0.0.
|
||||||
|
|
||||||
|
#### I'm having issues with Gmail
|
||||||
|
|
||||||
|
Gmail either works well, or it does not work at all. It is probably easier to switch to an alternative service instead of fixing issues with Gmail. If Gmail does not work for you, then don't use it. Read more about it [here](https://nodemailer.com/usage/using-gmail/).
|
||||||
|
|
||||||
|
#### I get ETIMEDOUT errors
|
||||||
|
|
||||||
|
Check your firewall settings. Timeout usually occurs when you try to open a connection to a firewalled port either on the server or on your machine. Some ISPs also block email ports to prevent spamming.
|
||||||
|
|
||||||
|
#### Nodemailer works on one machine but not in another
|
||||||
|
|
||||||
|
It's either a firewall issue, or your SMTP server blocks authentication attempts from some servers.
|
||||||
|
|
||||||
|
#### I get TLS errors
|
||||||
|
|
||||||
|
- If you are running the code on your machine, check your antivirus settings. Antiviruses often mess around with email ports usage. Node.js might not recognize the MITM cert your antivirus is using.
|
||||||
|
- Latest Node versions allow only TLS versions 1.2 and higher. Some servers might still use TLS 1.1 or lower. Check Node.js docs on how to get correct TLS support for your app. You can change this with [tls.minVersion](https://nodejs.org/dist/latest-v16.x/docs/api/tls.html#tls_tls_createsecurecontext_options) option
|
||||||
|
- You might have the wrong value for the `secure` option. This should be set to `true` only for port 465. For every other port, it should be `false`. Setting it to `false` does not mean that Nodemailer would not use TLS. Nodemailer would still try to upgrade the connection to use TLS if the server supports it.
|
||||||
|
- Older Node versions do not fully support the certificate chain of the newest Let's Encrypt certificates. Either set [tls.rejectUnauthorized](https://nodejs.org/dist/latest-v16.x/docs/api/tls.html#tlsconnectoptions-callback) to `false` to skip chain verification or upgrade your Node version
|
||||||
|
|
||||||
|
```js
|
||||||
|
let configOptions = {
|
||||||
|
host: 'smtp.example.com',
|
||||||
|
port: 587,
|
||||||
|
tls: {
|
||||||
|
rejectUnauthorized: true,
|
||||||
|
minVersion: 'TLSv1.2'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### I have issues with DNS / hosts file
|
||||||
|
|
||||||
|
Node.js uses [c-ares](https://nodejs.org/en/docs/meta/topics/dependencies/#c-ares) to resolve domain names, not the DNS library provided by the system, so if you have some custom DNS routing set up, it might be ignored. Nodemailer runs [dns.resolve4()](https://nodejs.org/dist/latest-v16.x/docs/api/dns.html#dnsresolve4hostname-options-callback) and [dns.resolve6()](https://nodejs.org/dist/latest-v16.x/docs/api/dns.html#dnsresolve6hostname-options-callback) to resolve hostname into an IP address. If both calls fail, then Nodemailer will fall back to [dns.lookup()](https://nodejs.org/dist/latest-v16.x/docs/api/dns.html#dnslookuphostname-options-callback). If this does not work for you, you can hard code the IP address into the configuration like shown below. In that case, Nodemailer would not perform any DNS lookups.
|
||||||
|
|
||||||
|
```js
|
||||||
|
let configOptions = {
|
||||||
|
host: '1.2.3.4',
|
||||||
|
port: 465,
|
||||||
|
secure: true,
|
||||||
|
tls: {
|
||||||
|
// must provide server name, otherwise TLS certificate check will fail
|
||||||
|
servername: 'example.com'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### I have an issue with TypeScript types
|
||||||
|
|
||||||
|
Nodemailer has official support for Node.js only. For anything related to TypeScript, you need to directly contact the authors of the [type definitions](https://www.npmjs.com/package/@types/nodemailer).
|
||||||
|
|
||||||
|
#### I have a different problem
|
||||||
|
|
||||||
|
If you are having issues with Nodemailer, then the best way to find help would be [Stack Overflow](https://stackoverflow.com/search?q=nodemailer) or revisit the [docs](https://nodemailer.com/about/).
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
Nodemailer is licensed under the **MIT No Attribution license**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The Nodemailer logo was designed by [Sven Kristjansen](https://www.behance.net/kristjansen).
|
||||||
22
node_modules/nodemailer/SECURITY.txt
generated
vendored
Normal file
22
node_modules/nodemailer/SECURITY.txt
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-----BEGIN PGP SIGNED MESSAGE-----
|
||||||
|
Hash: SHA256
|
||||||
|
|
||||||
|
Contact: mailto:andris@reinman.eu
|
||||||
|
Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/5D952A46E1D8C931F6364E01DC6C83F4D584D364
|
||||||
|
Preferred-Languages: en, et
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIzBAEBCAAdFiEEXZUqRuHYyTH2Nk4B3GyD9NWE02QFAmFDnUgACgkQ3GyD9NWE
|
||||||
|
02RqUA/+MM3afmRYq874C7wp+uN6dTMCvUX5g5zqBZ2yKpFr46L+PYvM7o8TMm5h
|
||||||
|
hmLT2I1zZmi+xezOL3zHFizaw0tKkZIz9cWl3Jrgs0FLp0zOsSz1xucp9Q2tYM/Q
|
||||||
|
vbiP6ys0gbim4tkDGRmZOEiO23s0BuRnmHt7vZg210O+D105Yd8/Ohzbj6PSLBO5
|
||||||
|
W1tA7Xw5t0FQ14NNH5+MKyDIKoCX12n0FmrC6qLTXeojf291UgKhCUPda3LIGTmx
|
||||||
|
mTXz0y68149Mw+JikRCYP8HfGRY9eA4XZrYXF7Bl2T9OJpKD3JAH+69P3xBw19Gn
|
||||||
|
Csaw3twu8P1bxoVGjY4KRrBOp68W8TwZYjWVWbqY6oV8hb/JfrMxa+kaSxRuloFs
|
||||||
|
oL6+phrDSPTWdOj2LlEDBJbPOMeDFzIlsBBcJ/JHCEHTvlHl7LoWr3YuWce9PUwl
|
||||||
|
4r3JUovvaeuJxLgC0vu3WCB3Jeocsl3SreqNkrVc1IjvkSomn3YGm5nCNAd/2F0V
|
||||||
|
exCGRk/8wbkSjAY38GwQ8K/VuFsefWN3L9sVwIMAMu88KFCAN+GzVFiwvyIXehF5
|
||||||
|
eogP9mIXzdQ5YReQjUjApOzGz54XnDyv9RJ3sdvMHosLP+IOg+0q5t9agWv6aqSR
|
||||||
|
2HzCpiQnH/gmM5NS0AU4Koq/L7IBeLu1B8+61/+BiHgZJJmPdgU=
|
||||||
|
=BUZr
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
88
node_modules/nodemailer/eslint.config.js
generated
vendored
Normal file
88
node_modules/nodemailer/eslint.config.js
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const globals = require('globals');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
ignores: ['node_modules/**', 'coverage/**', 'dist/**', 'build/**', '.nyc_output/**']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.js'],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2017,
|
||||||
|
sourceType: 'script',
|
||||||
|
globals: Object.assign({}, globals.node, globals.es2017, {
|
||||||
|
it: true,
|
||||||
|
describe: true,
|
||||||
|
beforeEach: true,
|
||||||
|
afterEach: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// Error detection
|
||||||
|
'for-direction': 'error',
|
||||||
|
'no-await-in-loop': 'error',
|
||||||
|
'no-div-regex': 'error',
|
||||||
|
eqeqeq: 'error',
|
||||||
|
'dot-notation': 'error',
|
||||||
|
curly: 'error',
|
||||||
|
'no-fallthrough': 'error',
|
||||||
|
'no-unused-expressions': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowShortCircuit: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'handle-callback-err': 'error',
|
||||||
|
'no-new': 'error',
|
||||||
|
'new-cap': 'error',
|
||||||
|
'no-eval': 'error',
|
||||||
|
'no-invalid-this': 'error',
|
||||||
|
radix: ['error', 'always'],
|
||||||
|
'no-use-before-define': ['error', 'nofunc'],
|
||||||
|
'callback-return': ['error', ['callback', 'cb', 'done']],
|
||||||
|
'no-regex-spaces': 'error',
|
||||||
|
'no-empty': 'error',
|
||||||
|
'no-duplicate-case': 'error',
|
||||||
|
'no-empty-character-class': 'error',
|
||||||
|
'no-redeclare': 'off', // Disabled per project preference
|
||||||
|
'block-scoped-var': 'error',
|
||||||
|
'no-sequences': 'error',
|
||||||
|
'no-throw-literal': 'error',
|
||||||
|
'no-useless-call': 'error',
|
||||||
|
'no-useless-concat': 'error',
|
||||||
|
'no-void': 'error',
|
||||||
|
yoda: 'error',
|
||||||
|
'no-undef': 'error',
|
||||||
|
'global-require': 'error',
|
||||||
|
'no-var': 'error',
|
||||||
|
'no-bitwise': 'error',
|
||||||
|
'no-lonely-if': 'error',
|
||||||
|
'no-mixed-spaces-and-tabs': 'error',
|
||||||
|
'arrow-body-style': ['error', 'as-needed'],
|
||||||
|
'arrow-parens': ['error', 'as-needed'],
|
||||||
|
'prefer-arrow-callback': 'error',
|
||||||
|
'object-shorthand': 'error',
|
||||||
|
'prefer-spread': 'error',
|
||||||
|
'no-prototype-builtins': 'off', // Disabled per project preference
|
||||||
|
strict: ['error', 'global'],
|
||||||
|
|
||||||
|
// Disable all formatting rules (handled by Prettier)
|
||||||
|
indent: 'off',
|
||||||
|
quotes: 'off',
|
||||||
|
'linebreak-style': 'off',
|
||||||
|
semi: 'off',
|
||||||
|
'quote-props': 'off',
|
||||||
|
'comma-dangle': 'off',
|
||||||
|
'comma-style': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
397
node_modules/nodemailer/lib/addressparser/index.js
generated
vendored
Normal file
397
node_modules/nodemailer/lib/addressparser/index.js
generated
vendored
Normal file
@ -0,0 +1,397 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts tokens for a single address into an address object
|
||||||
|
*
|
||||||
|
* @param {Array} tokens Tokens object
|
||||||
|
* @param {Number} depth Current recursion depth for nested group protection
|
||||||
|
* @return {Object} Address object
|
||||||
|
*/
|
||||||
|
function _handleAddress(tokens, depth) {
|
||||||
|
let isGroup = false;
|
||||||
|
let state = 'text';
|
||||||
|
let address;
|
||||||
|
let addresses = [];
|
||||||
|
let data = {
|
||||||
|
address: [],
|
||||||
|
comment: [],
|
||||||
|
group: [],
|
||||||
|
text: [],
|
||||||
|
textWasQuoted: [] // Track which text tokens came from inside quotes
|
||||||
|
};
|
||||||
|
let i;
|
||||||
|
let len;
|
||||||
|
let insideQuotes = false; // Track if we're currently inside a quoted string
|
||||||
|
|
||||||
|
// Filter out <addresses>, (comments) and regular text
|
||||||
|
for (i = 0, len = tokens.length; i < len; i++) {
|
||||||
|
let token = tokens[i];
|
||||||
|
let prevToken = i ? tokens[i - 1] : null;
|
||||||
|
if (token.type === 'operator') {
|
||||||
|
switch (token.value) {
|
||||||
|
case '<':
|
||||||
|
state = 'address';
|
||||||
|
insideQuotes = false;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
state = 'comment';
|
||||||
|
insideQuotes = false;
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
state = 'group';
|
||||||
|
isGroup = true;
|
||||||
|
insideQuotes = false;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
// Track quote state for text tokens
|
||||||
|
insideQuotes = !insideQuotes;
|
||||||
|
state = 'text';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state = 'text';
|
||||||
|
insideQuotes = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (token.value) {
|
||||||
|
if (state === 'address') {
|
||||||
|
// handle use case where unquoted name includes a "<"
|
||||||
|
// Apple Mail truncates everything between an unexpected < and an address
|
||||||
|
// and so will we
|
||||||
|
token.value = token.value.replace(/^[^<]*<\s*/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevToken && prevToken.noBreak && data[state].length) {
|
||||||
|
// join values
|
||||||
|
data[state][data[state].length - 1] += token.value;
|
||||||
|
if (state === 'text' && insideQuotes) {
|
||||||
|
data.textWasQuoted[data.textWasQuoted.length - 1] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data[state].push(token.value);
|
||||||
|
if (state === 'text') {
|
||||||
|
data.textWasQuoted.push(insideQuotes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no text but a comment, replace the two
|
||||||
|
if (!data.text.length && data.comment.length) {
|
||||||
|
data.text = data.comment;
|
||||||
|
data.comment = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGroup) {
|
||||||
|
// http://tools.ietf.org/html/rfc2822#appendix-A.1.3
|
||||||
|
data.text = data.text.join(' ');
|
||||||
|
|
||||||
|
// Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
|
||||||
|
let groupMembers = [];
|
||||||
|
if (data.group.length) {
|
||||||
|
let parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
|
||||||
|
// Flatten: if any member is itself a group, extract its members into the sequence
|
||||||
|
parsedGroup.forEach(member => {
|
||||||
|
if (member.group) {
|
||||||
|
// Nested group detected - flatten it by adding its members directly
|
||||||
|
groupMembers = groupMembers.concat(member.group);
|
||||||
|
} else {
|
||||||
|
groupMembers.push(member);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses.push({
|
||||||
|
name: data.text || (address && address.name),
|
||||||
|
group: groupMembers
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If no address was found, try to detect one from regular text
|
||||||
|
if (!data.address.length && data.text.length) {
|
||||||
|
for (i = data.text.length - 1; i >= 0; i--) {
|
||||||
|
// Security fix: Do not extract email addresses from quoted strings
|
||||||
|
// RFC 5321 allows @ inside quoted local-parts like "user@domain"@example.com
|
||||||
|
// Extracting emails from quoted text leads to misrouting vulnerabilities
|
||||||
|
if (!data.textWasQuoted[i] && data.text[i].match(/^[^@\s]+@[^@\s]+$/)) {
|
||||||
|
data.address = data.text.splice(i, 1);
|
||||||
|
data.textWasQuoted.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _regexHandler = function (address) {
|
||||||
|
if (!data.address.length) {
|
||||||
|
data.address = [address.trim()];
|
||||||
|
return ' ';
|
||||||
|
} else {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// still no address
|
||||||
|
if (!data.address.length) {
|
||||||
|
for (i = data.text.length - 1; i >= 0; i--) {
|
||||||
|
// Security fix: Do not extract email addresses from quoted strings
|
||||||
|
if (!data.textWasQuoted[i]) {
|
||||||
|
// fixed the regex to parse email address correctly when email address has more than one @
|
||||||
|
data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, _regexHandler).trim();
|
||||||
|
if (data.address.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's still is no text but a comment exixts, replace the two
|
||||||
|
if (!data.text.length && data.comment.length) {
|
||||||
|
data.text = data.comment;
|
||||||
|
data.comment = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep only the first address occurence, push others to regular text
|
||||||
|
if (data.address.length > 1) {
|
||||||
|
data.text = data.text.concat(data.address.splice(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join values with spaces
|
||||||
|
data.text = data.text.join(' ');
|
||||||
|
data.address = data.address.join(' ');
|
||||||
|
|
||||||
|
if (!data.address && isGroup) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
address = {
|
||||||
|
address: data.address || data.text || '',
|
||||||
|
name: data.text || data.address || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
if (address.address === address.name) {
|
||||||
|
if ((address.address || '').match(/@/)) {
|
||||||
|
address.name = '';
|
||||||
|
} else {
|
||||||
|
address.address = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses.push(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Tokenizer object for tokenizing address field strings
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {String} str Address field string
|
||||||
|
*/
|
||||||
|
class Tokenizer {
|
||||||
|
constructor(str) {
|
||||||
|
this.str = (str || '').toString();
|
||||||
|
this.operatorCurrent = '';
|
||||||
|
this.operatorExpecting = '';
|
||||||
|
this.node = null;
|
||||||
|
this.escaped = false;
|
||||||
|
|
||||||
|
this.list = [];
|
||||||
|
/**
|
||||||
|
* Operator tokens and which tokens are expected to end the sequence
|
||||||
|
*/
|
||||||
|
this.operators = {
|
||||||
|
'"': '"',
|
||||||
|
'(': ')',
|
||||||
|
'<': '>',
|
||||||
|
',': '',
|
||||||
|
':': ';',
|
||||||
|
// Semicolons are not a legal delimiter per the RFC2822 grammar other
|
||||||
|
// than for terminating a group, but they are also not valid for any
|
||||||
|
// other use in this context. Given that some mail clients have
|
||||||
|
// historically allowed the semicolon as a delimiter equivalent to the
|
||||||
|
// comma in their UI, it makes sense to treat them the same as a comma
|
||||||
|
// when used outside of a group.
|
||||||
|
';': ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tokenizes the original input string
|
||||||
|
*
|
||||||
|
* @return {Array} An array of operator|text tokens
|
||||||
|
*/
|
||||||
|
tokenize() {
|
||||||
|
let list = [];
|
||||||
|
|
||||||
|
for (let i = 0, len = this.str.length; i < len; i++) {
|
||||||
|
let chr = this.str.charAt(i);
|
||||||
|
let nextChr = i < len - 1 ? this.str.charAt(i + 1) : null;
|
||||||
|
this.checkChar(chr, nextChr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.list.forEach(node => {
|
||||||
|
node.value = (node.value || '').toString().trim();
|
||||||
|
if (node.value) {
|
||||||
|
list.push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a character is an operator or text and acts accordingly
|
||||||
|
*
|
||||||
|
* @param {String} chr Character from the address field
|
||||||
|
*/
|
||||||
|
checkChar(chr, nextChr) {
|
||||||
|
if (this.escaped) {
|
||||||
|
// ignore next condition blocks
|
||||||
|
} else if (chr === this.operatorExpecting) {
|
||||||
|
this.node = {
|
||||||
|
type: 'operator',
|
||||||
|
value: chr
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nextChr && ![' ', '\t', '\r', '\n', ',', ';'].includes(nextChr)) {
|
||||||
|
this.node.noBreak = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.list.push(this.node);
|
||||||
|
this.node = null;
|
||||||
|
this.operatorExpecting = '';
|
||||||
|
this.escaped = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (!this.operatorExpecting && chr in this.operators) {
|
||||||
|
this.node = {
|
||||||
|
type: 'operator',
|
||||||
|
value: chr
|
||||||
|
};
|
||||||
|
this.list.push(this.node);
|
||||||
|
this.node = null;
|
||||||
|
this.operatorExpecting = this.operators[chr];
|
||||||
|
this.escaped = false;
|
||||||
|
return;
|
||||||
|
} else if (['"', "'"].includes(this.operatorExpecting) && chr === '\\') {
|
||||||
|
this.escaped = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.node) {
|
||||||
|
this.node = {
|
||||||
|
type: 'text',
|
||||||
|
value: ''
|
||||||
|
};
|
||||||
|
this.list.push(this.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr === '\n') {
|
||||||
|
// Convert newlines to spaces. Carriage return is ignored as \r and \n usually
|
||||||
|
// go together anyway and there already is a WS for \n. Lone \r means something is fishy.
|
||||||
|
chr = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr.charCodeAt(0) >= 0x21 || [' ', '\t'].includes(chr)) {
|
||||||
|
// skip command bytes
|
||||||
|
this.node.value += chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.escaped = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum recursion depth for parsing nested groups.
|
||||||
|
* RFC 5322 doesn't allow nested groups, so this is a safeguard against
|
||||||
|
* malicious input that could cause stack overflow.
|
||||||
|
*/
|
||||||
|
const MAX_NESTED_GROUP_DEPTH = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses structured e-mail addresses from an address field
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* 'Name <address@domain>'
|
||||||
|
*
|
||||||
|
* will be converted to
|
||||||
|
*
|
||||||
|
* [{name: 'Name', address: 'address@domain'}]
|
||||||
|
*
|
||||||
|
* @param {String} str Address field
|
||||||
|
* @param {Object} options Optional options object
|
||||||
|
* @param {Number} options._depth Internal recursion depth counter (do not set manually)
|
||||||
|
* @return {Array} An array of address objects
|
||||||
|
*/
|
||||||
|
function addressparser(str, options) {
|
||||||
|
options = options || {};
|
||||||
|
let depth = options._depth || 0;
|
||||||
|
|
||||||
|
// Prevent stack overflow from deeply nested groups (DoS protection)
|
||||||
|
if (depth > MAX_NESTED_GROUP_DEPTH) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let tokenizer = new Tokenizer(str);
|
||||||
|
let tokens = tokenizer.tokenize();
|
||||||
|
|
||||||
|
let addresses = [];
|
||||||
|
let address = [];
|
||||||
|
let parsedAddresses = [];
|
||||||
|
|
||||||
|
tokens.forEach(token => {
|
||||||
|
if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
|
||||||
|
if (address.length) {
|
||||||
|
addresses.push(address);
|
||||||
|
}
|
||||||
|
address = [];
|
||||||
|
} else {
|
||||||
|
address.push(token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (address.length) {
|
||||||
|
addresses.push(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses.forEach(address => {
|
||||||
|
address = _handleAddress(address, depth);
|
||||||
|
if (address.length) {
|
||||||
|
parsedAddresses = parsedAddresses.concat(address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge fragments from unquoted display names containing commas/semicolons.
|
||||||
|
// When "Joe Foo, PhD <joe@example.com>" is split on the comma, it produces
|
||||||
|
// [{name:"Joe Foo", address:""}, {name:"PhD", address:"joe@example.com"}].
|
||||||
|
// Detect this pattern and recombine: a name-only entry followed by an entry
|
||||||
|
// that has both a name and an address (from angle-bracket notation).
|
||||||
|
for (let i = parsedAddresses.length - 2; i >= 0; i--) {
|
||||||
|
let current = parsedAddresses[i];
|
||||||
|
let next = parsedAddresses[i + 1];
|
||||||
|
if (current.address === '' && current.name && !current.group && next.address && next.name && !next.group) {
|
||||||
|
next.name = current.name + ', ' + next.name;
|
||||||
|
parsedAddresses.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.flatten) {
|
||||||
|
let addresses = [];
|
||||||
|
let walkAddressList = list => {
|
||||||
|
list.forEach(address => {
|
||||||
|
if (address.group) {
|
||||||
|
return walkAddressList(address.group);
|
||||||
|
} else {
|
||||||
|
addresses.push(address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
walkAddressList(parsedAddresses);
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expose to the world
|
||||||
|
module.exports = addressparser;
|
||||||
139
node_modules/nodemailer/lib/base64/index.js
generated
vendored
Normal file
139
node_modules/nodemailer/lib/base64/index.js
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Transform = require('stream').Transform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a Buffer into a base64 encoded string
|
||||||
|
*
|
||||||
|
* @param {Buffer} buffer Buffer to convert
|
||||||
|
* @returns {String} base64 encoded string
|
||||||
|
*/
|
||||||
|
function encode(buffer) {
|
||||||
|
if (typeof buffer === 'string') {
|
||||||
|
buffer = Buffer.from(buffer, 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds soft line breaks to a base64 string
|
||||||
|
*
|
||||||
|
* @param {String} str base64 encoded string that might need line wrapping
|
||||||
|
* @param {Number} [lineLength=76] Maximum allowed length for a line
|
||||||
|
* @returns {String} Soft-wrapped base64 encoded string
|
||||||
|
*/
|
||||||
|
function wrap(str, lineLength) {
|
||||||
|
str = (str || '').toString();
|
||||||
|
lineLength = lineLength || 76;
|
||||||
|
|
||||||
|
if (str.length <= lineLength) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
let pos = 0;
|
||||||
|
let chunkLength = lineLength * 1024;
|
||||||
|
while (pos < str.length) {
|
||||||
|
let wrappedLines = str.substr(pos, chunkLength).replace(new RegExp('.{' + lineLength + '}', 'g'), '$&\r\n');
|
||||||
|
result.push(wrappedLines);
|
||||||
|
pos += chunkLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform stream for encoding data to base64 encoding
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} options Stream options
|
||||||
|
* @param {Number} [options.lineLength=76] Maximum length for lines, set to false to disable wrapping
|
||||||
|
*/
|
||||||
|
class Encoder extends Transform {
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
this.options = options || {};
|
||||||
|
|
||||||
|
if (this.options.lineLength !== false) {
|
||||||
|
this.options.lineLength = this.options.lineLength || 76;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._curLine = '';
|
||||||
|
this._remainingBytes = false;
|
||||||
|
|
||||||
|
this.inputBytes = 0;
|
||||||
|
this.outputBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_transform(chunk, encoding, done) {
|
||||||
|
if (encoding !== 'buffer') {
|
||||||
|
chunk = Buffer.from(chunk, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chunk || !chunk.length) {
|
||||||
|
return setImmediate(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inputBytes += chunk.length;
|
||||||
|
|
||||||
|
if (this._remainingBytes && this._remainingBytes.length) {
|
||||||
|
chunk = Buffer.concat([this._remainingBytes, chunk], this._remainingBytes.length + chunk.length);
|
||||||
|
this._remainingBytes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.length % 3) {
|
||||||
|
this._remainingBytes = chunk.slice(chunk.length - (chunk.length % 3));
|
||||||
|
chunk = chunk.slice(0, chunk.length - (chunk.length % 3));
|
||||||
|
} else {
|
||||||
|
this._remainingBytes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let b64 = this._curLine + encode(chunk);
|
||||||
|
|
||||||
|
if (this.options.lineLength) {
|
||||||
|
b64 = wrap(b64, this.options.lineLength);
|
||||||
|
|
||||||
|
let lastLF = b64.lastIndexOf('\n');
|
||||||
|
if (lastLF < 0) {
|
||||||
|
this._curLine = b64;
|
||||||
|
b64 = '';
|
||||||
|
} else {
|
||||||
|
this._curLine = b64.substring(lastLF + 1);
|
||||||
|
b64 = b64.substring(0, lastLF + 1);
|
||||||
|
|
||||||
|
if (b64 && !b64.endsWith('\r\n')) {
|
||||||
|
b64 += '\r\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._curLine = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b64) {
|
||||||
|
this.outputBytes += b64.length;
|
||||||
|
this.push(Buffer.from(b64, 'ascii'));
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
_flush(done) {
|
||||||
|
if (this._remainingBytes && this._remainingBytes.length) {
|
||||||
|
this._curLine += encode(this._remainingBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._curLine) {
|
||||||
|
this.outputBytes += this._curLine.length;
|
||||||
|
this.push(Buffer.from(this._curLine, 'ascii'));
|
||||||
|
this._curLine = '';
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
encode,
|
||||||
|
wrap,
|
||||||
|
Encoder
|
||||||
|
};
|
||||||
253
node_modules/nodemailer/lib/dkim/index.js
generated
vendored
Normal file
253
node_modules/nodemailer/lib/dkim/index.js
generated
vendored
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// replace this Transform mess with a method that pipes input argument to output argument
|
||||||
|
|
||||||
|
const MessageParser = require('./message-parser');
|
||||||
|
const RelaxedBody = require('./relaxed-body');
|
||||||
|
const sign = require('./sign');
|
||||||
|
const PassThrough = require('stream').PassThrough;
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const DKIM_ALGO = 'sha256';
|
||||||
|
const MAX_MESSAGE_SIZE = 2 * 1024 * 1024; // buffer messages larger than this to disk
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Usage:
|
||||||
|
|
||||||
|
let dkim = new DKIM({
|
||||||
|
domainName: 'example.com',
|
||||||
|
keySelector: 'key-selector',
|
||||||
|
privateKey,
|
||||||
|
cacheDir: '/tmp'
|
||||||
|
});
|
||||||
|
dkim.sign(input).pipe(process.stdout);
|
||||||
|
|
||||||
|
// Where inputStream is a rfc822 message (either a stream, string or Buffer)
|
||||||
|
// and outputStream is a DKIM signed rfc822 message
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DKIMSigner {
|
||||||
|
constructor(options, keys, input, output) {
|
||||||
|
this.options = options || {};
|
||||||
|
this.keys = keys;
|
||||||
|
|
||||||
|
this.cacheTreshold = Number(this.options.cacheTreshold) || MAX_MESSAGE_SIZE;
|
||||||
|
this.hashAlgo = this.options.hashAlgo || DKIM_ALGO;
|
||||||
|
|
||||||
|
this.cacheDir = this.options.cacheDir || false;
|
||||||
|
|
||||||
|
this.chunks = [];
|
||||||
|
this.chunklen = 0;
|
||||||
|
this.readPos = 0;
|
||||||
|
this.cachePath = this.cacheDir
|
||||||
|
? path.join(this.cacheDir, 'message.' + Date.now() + '-' + crypto.randomBytes(14).toString('hex'))
|
||||||
|
: false;
|
||||||
|
this.cache = false;
|
||||||
|
|
||||||
|
this.headers = false;
|
||||||
|
this.bodyHash = false;
|
||||||
|
this.parser = false;
|
||||||
|
this.relaxedBody = false;
|
||||||
|
|
||||||
|
this.input = input;
|
||||||
|
this.output = output;
|
||||||
|
this.output.usingCache = false;
|
||||||
|
|
||||||
|
this.hasErrored = false;
|
||||||
|
|
||||||
|
this.input.on('error', err => {
|
||||||
|
this.hasErrored = true;
|
||||||
|
this.cleanup();
|
||||||
|
output.emit('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if (!this.cache || !this.cachePath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs.unlink(this.cachePath, () => false);
|
||||||
|
}
|
||||||
|
|
||||||
|
createReadCache() {
|
||||||
|
// pipe remainings to cache file
|
||||||
|
this.cache = fs.createReadStream(this.cachePath);
|
||||||
|
this.cache.once('error', err => {
|
||||||
|
this.cleanup();
|
||||||
|
this.output.emit('error', err);
|
||||||
|
});
|
||||||
|
this.cache.once('close', () => {
|
||||||
|
this.cleanup();
|
||||||
|
});
|
||||||
|
this.cache.pipe(this.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNextChunk() {
|
||||||
|
if (this.hasErrored) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.readPos >= this.chunks.length) {
|
||||||
|
if (!this.cache) {
|
||||||
|
return this.output.end();
|
||||||
|
}
|
||||||
|
return this.createReadCache();
|
||||||
|
}
|
||||||
|
let chunk = this.chunks[this.readPos++];
|
||||||
|
if (this.output.write(chunk) === false) {
|
||||||
|
return this.output.once('drain', () => {
|
||||||
|
this.sendNextChunk();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setImmediate(() => this.sendNextChunk());
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSignedOutput() {
|
||||||
|
let keyPos = 0;
|
||||||
|
let signNextKey = () => {
|
||||||
|
if (keyPos >= this.keys.length) {
|
||||||
|
this.output.write(this.parser.rawHeaders);
|
||||||
|
return setImmediate(() => this.sendNextChunk());
|
||||||
|
}
|
||||||
|
let key = this.keys[keyPos++];
|
||||||
|
let dkimField = sign(this.headers, this.hashAlgo, this.bodyHash, {
|
||||||
|
domainName: key.domainName,
|
||||||
|
keySelector: key.keySelector,
|
||||||
|
privateKey: key.privateKey,
|
||||||
|
headerFieldNames: this.options.headerFieldNames,
|
||||||
|
skipFields: this.options.skipFields
|
||||||
|
});
|
||||||
|
if (dkimField) {
|
||||||
|
this.output.write(Buffer.from(dkimField + '\r\n'));
|
||||||
|
}
|
||||||
|
return setImmediate(signNextKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.bodyHash && this.headers) {
|
||||||
|
return signNextKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.output.write(this.parser.rawHeaders);
|
||||||
|
this.sendNextChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
createWriteCache() {
|
||||||
|
this.output.usingCache = true;
|
||||||
|
// pipe remainings to cache file
|
||||||
|
this.cache = fs.createWriteStream(this.cachePath);
|
||||||
|
this.cache.once('error', err => {
|
||||||
|
this.cleanup();
|
||||||
|
// drain input
|
||||||
|
this.relaxedBody.unpipe(this.cache);
|
||||||
|
this.relaxedBody.on('readable', () => {
|
||||||
|
while (this.relaxedBody.read() !== null) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.hasErrored = true;
|
||||||
|
// emit error
|
||||||
|
this.output.emit('error', err);
|
||||||
|
});
|
||||||
|
this.cache.once('close', () => {
|
||||||
|
this.sendSignedOutput();
|
||||||
|
});
|
||||||
|
this.relaxedBody.removeAllListeners('readable');
|
||||||
|
this.relaxedBody.pipe(this.cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
signStream() {
|
||||||
|
this.parser = new MessageParser();
|
||||||
|
this.relaxedBody = new RelaxedBody({
|
||||||
|
hashAlgo: this.hashAlgo
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parser.on('headers', value => {
|
||||||
|
this.headers = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.relaxedBody.on('hash', value => {
|
||||||
|
this.bodyHash = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.relaxedBody.on('readable', () => {
|
||||||
|
let chunk;
|
||||||
|
if (this.cache) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((chunk = this.relaxedBody.read()) !== null) {
|
||||||
|
this.chunks.push(chunk);
|
||||||
|
this.chunklen += chunk.length;
|
||||||
|
if (this.chunklen >= this.cacheTreshold && this.cachePath) {
|
||||||
|
return this.createWriteCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.relaxedBody.on('end', () => {
|
||||||
|
if (this.cache) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendSignedOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parser.pipe(this.relaxedBody);
|
||||||
|
setImmediate(() => this.input.pipe(this.parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DKIM {
|
||||||
|
constructor(options) {
|
||||||
|
this.options = options || {};
|
||||||
|
this.keys = [].concat(
|
||||||
|
this.options.keys || {
|
||||||
|
domainName: options.domainName,
|
||||||
|
keySelector: options.keySelector,
|
||||||
|
privateKey: options.privateKey
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sign(input, extraOptions) {
|
||||||
|
let output = new PassThrough();
|
||||||
|
let inputStream = input;
|
||||||
|
let writeValue = false;
|
||||||
|
|
||||||
|
if (Buffer.isBuffer(input)) {
|
||||||
|
writeValue = input;
|
||||||
|
inputStream = new PassThrough();
|
||||||
|
} else if (typeof input === 'string') {
|
||||||
|
writeValue = Buffer.from(input);
|
||||||
|
inputStream = new PassThrough();
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = this.options;
|
||||||
|
if (extraOptions && Object.keys(extraOptions).length) {
|
||||||
|
options = {};
|
||||||
|
Object.keys(this.options || {}).forEach(key => {
|
||||||
|
options[key] = this.options[key];
|
||||||
|
});
|
||||||
|
Object.keys(extraOptions || {}).forEach(key => {
|
||||||
|
if (!(key in options)) {
|
||||||
|
options[key] = extraOptions[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let signer = new DKIMSigner(options, this.keys, inputStream, output);
|
||||||
|
setImmediate(() => {
|
||||||
|
signer.signStream();
|
||||||
|
if (writeValue) {
|
||||||
|
setImmediate(() => {
|
||||||
|
inputStream.end(writeValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DKIM;
|
||||||
155
node_modules/nodemailer/lib/dkim/message-parser.js
generated
vendored
Normal file
155
node_modules/nodemailer/lib/dkim/message-parser.js
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Transform = require('stream').Transform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageParser instance is a transform stream that separates message headers
|
||||||
|
* from the rest of the body. Headers are emitted with the 'headers' event. Message
|
||||||
|
* body is passed on as the resulting stream.
|
||||||
|
*/
|
||||||
|
class MessageParser extends Transform {
|
||||||
|
constructor(options) {
|
||||||
|
super(options);
|
||||||
|
this.lastBytes = Buffer.alloc(4);
|
||||||
|
this.headersParsed = false;
|
||||||
|
this.headerBytes = 0;
|
||||||
|
this.headerChunks = [];
|
||||||
|
this.rawHeaders = false;
|
||||||
|
this.bodySize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps count of the last 4 bytes in order to detect line breaks on chunk boundaries
|
||||||
|
*
|
||||||
|
* @param {Buffer} data Next data chunk from the stream
|
||||||
|
*/
|
||||||
|
updateLastBytes(data) {
|
||||||
|
let lblen = this.lastBytes.length;
|
||||||
|
let nblen = Math.min(data.length, lblen);
|
||||||
|
|
||||||
|
// shift existing bytes
|
||||||
|
for (let i = 0, len = lblen - nblen; i < len; i++) {
|
||||||
|
this.lastBytes[i] = this.lastBytes[i + nblen];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new bytes
|
||||||
|
for (let i = 1; i <= nblen; i++) {
|
||||||
|
this.lastBytes[lblen - i] = data[data.length - i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and removes message headers from the remaining body. We want to keep
|
||||||
|
* headers separated until final delivery to be able to modify these
|
||||||
|
*
|
||||||
|
* @param {Buffer} data Next chunk of data
|
||||||
|
* @return {Boolean} Returns true if headers are already found or false otherwise
|
||||||
|
*/
|
||||||
|
checkHeaders(data) {
|
||||||
|
if (this.headersParsed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lblen = this.lastBytes.length;
|
||||||
|
let headerPos = 0;
|
||||||
|
this.curLinePos = 0;
|
||||||
|
for (let i = 0, len = this.lastBytes.length + data.length; i < len; i++) {
|
||||||
|
let chr;
|
||||||
|
if (i < lblen) {
|
||||||
|
chr = this.lastBytes[i];
|
||||||
|
} else {
|
||||||
|
chr = data[i - lblen];
|
||||||
|
}
|
||||||
|
if (chr === 0x0a && i) {
|
||||||
|
let pr1 = i - 1 < lblen ? this.lastBytes[i - 1] : data[i - 1 - lblen];
|
||||||
|
let pr2 = i > 1 ? (i - 2 < lblen ? this.lastBytes[i - 2] : data[i - 2 - lblen]) : false;
|
||||||
|
if (pr1 === 0x0a) {
|
||||||
|
this.headersParsed = true;
|
||||||
|
headerPos = i - lblen + 1;
|
||||||
|
this.headerBytes += headerPos;
|
||||||
|
break;
|
||||||
|
} else if (pr1 === 0x0d && pr2 === 0x0a) {
|
||||||
|
this.headersParsed = true;
|
||||||
|
headerPos = i - lblen + 1;
|
||||||
|
this.headerBytes += headerPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.headersParsed) {
|
||||||
|
this.headerChunks.push(data.slice(0, headerPos));
|
||||||
|
this.rawHeaders = Buffer.concat(this.headerChunks, this.headerBytes);
|
||||||
|
this.headerChunks = null;
|
||||||
|
this.emit('headers', this.parseHeaders());
|
||||||
|
if (data.length - 1 > headerPos) {
|
||||||
|
let chunk = data.slice(headerPos);
|
||||||
|
this.bodySize += chunk.length;
|
||||||
|
// this would be the first chunk of data sent downstream
|
||||||
|
setImmediate(() => this.push(chunk));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
this.headerBytes += data.length;
|
||||||
|
this.headerChunks.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// store last 4 bytes to catch header break
|
||||||
|
this.updateLastBytes(data);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_transform(chunk, encoding, callback) {
|
||||||
|
if (!chunk || !chunk.length) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof chunk === 'string') {
|
||||||
|
chunk = Buffer.from(chunk, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
let headersFound;
|
||||||
|
|
||||||
|
try {
|
||||||
|
headersFound = this.checkHeaders(chunk);
|
||||||
|
} catch (E) {
|
||||||
|
return callback(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headersFound) {
|
||||||
|
this.bodySize += chunk.length;
|
||||||
|
this.push(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
_flush(callback) {
|
||||||
|
if (this.headerChunks) {
|
||||||
|
let chunk = Buffer.concat(this.headerChunks, this.headerBytes);
|
||||||
|
this.bodySize += chunk.length;
|
||||||
|
this.push(chunk);
|
||||||
|
this.headerChunks = null;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
parseHeaders() {
|
||||||
|
let lines = (this.rawHeaders || '').toString().split(/\r?\n/);
|
||||||
|
for (let i = lines.length - 1; i > 0; i--) {
|
||||||
|
if (/^\s/.test(lines[i])) {
|
||||||
|
lines[i - 1] += '\n' + lines[i];
|
||||||
|
lines.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
.filter(line => line.trim())
|
||||||
|
.map(line => ({
|
||||||
|
key: line.substr(0, line.indexOf(':')).trim().toLowerCase(),
|
||||||
|
line
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MessageParser;
|
||||||
154
node_modules/nodemailer/lib/dkim/relaxed-body.js
generated
vendored
Normal file
154
node_modules/nodemailer/lib/dkim/relaxed-body.js
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// streams through a message body and calculates relaxed body hash
|
||||||
|
|
||||||
|
const Transform = require('stream').Transform;
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
class RelaxedBody extends Transform {
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
options = options || {};
|
||||||
|
this.chunkBuffer = [];
|
||||||
|
this.chunkBufferLen = 0;
|
||||||
|
this.bodyHash = crypto.createHash(options.hashAlgo || 'sha1');
|
||||||
|
this.remainder = '';
|
||||||
|
this.byteLength = 0;
|
||||||
|
|
||||||
|
this.debug = options.debug;
|
||||||
|
this._debugBody = options.debug ? [] : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHash(chunk) {
|
||||||
|
let bodyStr;
|
||||||
|
|
||||||
|
// find next remainder
|
||||||
|
let nextRemainder = '';
|
||||||
|
|
||||||
|
// This crux finds and removes the spaces from the last line and the newline characters after the last non-empty line
|
||||||
|
// If we get another chunk that does not match this description then we can restore the previously processed data
|
||||||
|
let state = 'file';
|
||||||
|
for (let i = chunk.length - 1; i >= 0; i--) {
|
||||||
|
let c = chunk[i];
|
||||||
|
|
||||||
|
if (state === 'file' && (c === 0x0a || c === 0x0d)) {
|
||||||
|
// do nothing, found \n or \r at the end of chunk, stil end of file
|
||||||
|
} else if (state === 'file' && (c === 0x09 || c === 0x20)) {
|
||||||
|
// switch to line ending mode, this is the last non-empty line
|
||||||
|
state = 'line';
|
||||||
|
} else if (state === 'line' && (c === 0x09 || c === 0x20)) {
|
||||||
|
// do nothing, found ' ' or \t at the end of line, keep processing the last non-empty line
|
||||||
|
} else if (state === 'file' || state === 'line') {
|
||||||
|
// non line/file ending character found, switch to body mode
|
||||||
|
state = 'body';
|
||||||
|
if (i === chunk.length - 1) {
|
||||||
|
// final char is not part of line end or file end, so do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
// reached to the beginning of the chunk, check if it is still about the ending
|
||||||
|
// and if the remainder also matches
|
||||||
|
if (
|
||||||
|
(state === 'file' && (!this.remainder || /[\r\n]$/.test(this.remainder))) ||
|
||||||
|
(state === 'line' && (!this.remainder || /[ \t]$/.test(this.remainder)))
|
||||||
|
) {
|
||||||
|
// keep everything
|
||||||
|
this.remainder += chunk.toString('binary');
|
||||||
|
return;
|
||||||
|
} else if (state === 'line' || state === 'file') {
|
||||||
|
// process existing remainder as normal line but store the current chunk
|
||||||
|
nextRemainder = chunk.toString('binary');
|
||||||
|
chunk = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state !== 'body') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reached first non ending byte
|
||||||
|
nextRemainder = chunk.slice(i + 1).toString('binary');
|
||||||
|
chunk = chunk.slice(0, i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let needsFixing = !!this.remainder;
|
||||||
|
if (chunk && !needsFixing) {
|
||||||
|
// check if we even need to change anything
|
||||||
|
for (let i = 0, len = chunk.length; i < len; i++) {
|
||||||
|
if (i && chunk[i] === 0x0a && chunk[i - 1] !== 0x0d) {
|
||||||
|
// missing \r before \n
|
||||||
|
needsFixing = true;
|
||||||
|
break;
|
||||||
|
} else if (i && chunk[i] === 0x0d && chunk[i - 1] === 0x20) {
|
||||||
|
// trailing WSP found
|
||||||
|
needsFixing = true;
|
||||||
|
break;
|
||||||
|
} else if (i && chunk[i] === 0x20 && chunk[i - 1] === 0x20) {
|
||||||
|
// multiple spaces found, needs to be replaced with just one
|
||||||
|
needsFixing = true;
|
||||||
|
break;
|
||||||
|
} else if (chunk[i] === 0x09) {
|
||||||
|
// TAB found, needs to be replaced with a space
|
||||||
|
needsFixing = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsFixing) {
|
||||||
|
bodyStr = this.remainder + (chunk ? chunk.toString('binary') : '');
|
||||||
|
this.remainder = nextRemainder;
|
||||||
|
bodyStr = bodyStr
|
||||||
|
.replace(/\r?\n/g, '\n') // use js line endings
|
||||||
|
.replace(/[ \t]*$/gm, '') // remove line endings, rtrim
|
||||||
|
.replace(/[ \t]+/gm, ' ') // single spaces
|
||||||
|
.replace(/\n/g, '\r\n'); // restore rfc822 line endings
|
||||||
|
chunk = Buffer.from(bodyStr, 'binary');
|
||||||
|
} else if (nextRemainder) {
|
||||||
|
this.remainder = nextRemainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.debug) {
|
||||||
|
this._debugBody.push(chunk);
|
||||||
|
}
|
||||||
|
this.bodyHash.update(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
_transform(chunk, encoding, callback) {
|
||||||
|
if (!chunk || !chunk.length) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof chunk === 'string') {
|
||||||
|
chunk = Buffer.from(chunk, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateHash(chunk);
|
||||||
|
|
||||||
|
this.byteLength += chunk.length;
|
||||||
|
this.push(chunk);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
_flush(callback) {
|
||||||
|
// generate final hash and emit it
|
||||||
|
if (/[\r\n]$/.test(this.remainder) && this.byteLength > 2) {
|
||||||
|
// add terminating line end
|
||||||
|
this.bodyHash.update(Buffer.from('\r\n'));
|
||||||
|
}
|
||||||
|
if (!this.byteLength) {
|
||||||
|
// emit empty line buffer to keep the stream flowing
|
||||||
|
this.push(Buffer.from('\r\n'));
|
||||||
|
// this.bodyHash.update(Buffer.from('\r\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('hash', this.bodyHash.digest('base64'), this.debug ? Buffer.concat(this._debugBody) : false);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = RelaxedBody;
|
||||||
117
node_modules/nodemailer/lib/dkim/sign.js
generated
vendored
Normal file
117
node_modules/nodemailer/lib/dkim/sign.js
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const punycode = require('../punycode');
|
||||||
|
const mimeFuncs = require('../mime-funcs');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns DKIM signature header line
|
||||||
|
*
|
||||||
|
* @param {Object} headers Parsed headers object from MessageParser
|
||||||
|
* @param {String} bodyHash Base64 encoded hash of the message
|
||||||
|
* @param {Object} options DKIM options
|
||||||
|
* @param {String} options.domainName Domain name to be signed for
|
||||||
|
* @param {String} options.keySelector DKIM key selector to use
|
||||||
|
* @param {String} options.privateKey DKIM private key to use
|
||||||
|
* @return {String} Complete header line
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (headers, hashAlgo, bodyHash, options) => {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// all listed fields from RFC4871 #5.5
|
||||||
|
let defaultFieldNames =
|
||||||
|
'From:Sender:Reply-To:Subject:Date:Message-ID:To:' +
|
||||||
|
'Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:' +
|
||||||
|
'Content-Description:Resent-Date:Resent-From:Resent-Sender:' +
|
||||||
|
'Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:' +
|
||||||
|
'List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:' +
|
||||||
|
'List-Owner:List-Archive';
|
||||||
|
|
||||||
|
let fieldNames = options.headerFieldNames || defaultFieldNames;
|
||||||
|
|
||||||
|
let canonicalizedHeaderData = relaxedHeaders(headers, fieldNames, options.skipFields);
|
||||||
|
let dkimHeader = generateDKIMHeader(options.domainName, options.keySelector, canonicalizedHeaderData.fieldNames, hashAlgo, bodyHash);
|
||||||
|
|
||||||
|
let signer, signature;
|
||||||
|
|
||||||
|
canonicalizedHeaderData.headers += 'dkim-signature:' + relaxedHeaderLine(dkimHeader);
|
||||||
|
|
||||||
|
signer = crypto.createSign(('rsa-' + hashAlgo).toUpperCase());
|
||||||
|
signer.update(canonicalizedHeaderData.headers);
|
||||||
|
try {
|
||||||
|
signature = signer.sign(options.privateKey, 'base64');
|
||||||
|
} catch (_E) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dkimHeader + signature.replace(/(^.{73}|.{75}(?!\r?\n|\r))/g, '$&\r\n ').trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.relaxedHeaders = relaxedHeaders;
|
||||||
|
|
||||||
|
function generateDKIMHeader(domainName, keySelector, fieldNames, hashAlgo, bodyHash) {
|
||||||
|
let dkim = [
|
||||||
|
'v=1',
|
||||||
|
'a=rsa-' + hashAlgo,
|
||||||
|
'c=relaxed/relaxed',
|
||||||
|
'd=' + punycode.toASCII(domainName),
|
||||||
|
'q=dns/txt',
|
||||||
|
's=' + keySelector,
|
||||||
|
'bh=' + bodyHash,
|
||||||
|
'h=' + fieldNames
|
||||||
|
].join('; ');
|
||||||
|
|
||||||
|
return mimeFuncs.foldLines('DKIM-Signature: ' + dkim, 76) + ';\r\n b=';
|
||||||
|
}
|
||||||
|
|
||||||
|
function relaxedHeaders(headers, fieldNames, skipFields) {
|
||||||
|
let includedFields = new Set();
|
||||||
|
let skip = new Set();
|
||||||
|
let headerFields = new Map();
|
||||||
|
|
||||||
|
(skipFields || '')
|
||||||
|
.toLowerCase()
|
||||||
|
.split(':')
|
||||||
|
.forEach(field => {
|
||||||
|
skip.add(field.trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
(fieldNames || '')
|
||||||
|
.toLowerCase()
|
||||||
|
.split(':')
|
||||||
|
.filter(field => !skip.has(field.trim()))
|
||||||
|
.forEach(field => {
|
||||||
|
includedFields.add(field.trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = headers.length - 1; i >= 0; i--) {
|
||||||
|
let line = headers[i];
|
||||||
|
// only include the first value from bottom to top
|
||||||
|
if (includedFields.has(line.key) && !headerFields.has(line.key)) {
|
||||||
|
headerFields.set(line.key, relaxedHeaderLine(line.line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let headersList = [];
|
||||||
|
let fields = [];
|
||||||
|
includedFields.forEach(field => {
|
||||||
|
if (headerFields.has(field)) {
|
||||||
|
fields.push(field);
|
||||||
|
headersList.push(field + ':' + headerFields.get(field));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
headers: headersList.join('\r\n') + '\r\n',
|
||||||
|
fieldNames: fields.join(':')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function relaxedHeaderLine(line) {
|
||||||
|
return line
|
||||||
|
.substr(line.indexOf(':') + 1)
|
||||||
|
.replace(/\r?\n/g, '')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
61
node_modules/nodemailer/lib/errors.js
generated
vendored
Normal file
61
node_modules/nodemailer/lib/errors.js
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nodemailer Error Codes
|
||||||
|
*
|
||||||
|
* Centralized error code definitions for consistent error handling.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* const errors = require('./errors');
|
||||||
|
* let err = new Error('Connection closed');
|
||||||
|
* err.code = errors.ECONNECTION;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code descriptions for documentation and debugging
|
||||||
|
*/
|
||||||
|
const ERROR_CODES = {
|
||||||
|
// Connection errors
|
||||||
|
ECONNECTION: 'Connection closed unexpectedly',
|
||||||
|
ETIMEDOUT: 'Connection or operation timed out',
|
||||||
|
ESOCKET: 'Socket-level error',
|
||||||
|
EDNS: 'DNS resolution failed',
|
||||||
|
|
||||||
|
// TLS/Security errors
|
||||||
|
ETLS: 'TLS handshake or STARTTLS failed',
|
||||||
|
EREQUIRETLS: 'REQUIRETLS not supported by server (RFC 8689)',
|
||||||
|
|
||||||
|
// Protocol errors
|
||||||
|
EPROTOCOL: 'Invalid SMTP server response',
|
||||||
|
EENVELOPE: 'Invalid mail envelope (sender or recipients)',
|
||||||
|
EMESSAGE: 'Message delivery error',
|
||||||
|
ESTREAM: 'Stream processing error',
|
||||||
|
|
||||||
|
// Authentication errors
|
||||||
|
EAUTH: 'Authentication failed',
|
||||||
|
ENOAUTH: 'Authentication credentials not provided',
|
||||||
|
EOAUTH2: 'OAuth2 token generation or refresh error',
|
||||||
|
|
||||||
|
// Resource errors
|
||||||
|
EMAXLIMIT: 'Pool resource limit reached (max messages per connection)',
|
||||||
|
|
||||||
|
// Transport-specific errors
|
||||||
|
ESENDMAIL: 'Sendmail command error',
|
||||||
|
ESES: 'AWS SES transport error',
|
||||||
|
|
||||||
|
// Configuration and access errors
|
||||||
|
ECONFIG: 'Invalid configuration',
|
||||||
|
EPROXY: 'Proxy connection error',
|
||||||
|
EFILEACCESS: 'File access rejected (disableFileAccess is set)',
|
||||||
|
EURLACCESS: 'URL access rejected (disableUrlAccess is set)',
|
||||||
|
EFETCH: 'HTTP fetch error'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export error codes as string constants and the full definitions object
|
||||||
|
module.exports = Object.keys(ERROR_CODES).reduce(
|
||||||
|
(exports, code) => {
|
||||||
|
exports[code] = code;
|
||||||
|
return exports;
|
||||||
|
},
|
||||||
|
{ ERROR_CODES }
|
||||||
|
);
|
||||||
281
node_modules/nodemailer/lib/fetch/cookies.js
generated
vendored
Normal file
281
node_modules/nodemailer/lib/fetch/cookies.js
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// module to handle cookies
|
||||||
|
|
||||||
|
const urllib = require('url');
|
||||||
|
|
||||||
|
const SESSION_TIMEOUT = 1800; // 30 min
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a biskviit cookie jar for managing cookie values in memory
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} [options] Optional options object
|
||||||
|
*/
|
||||||
|
class Cookies {
|
||||||
|
constructor(options) {
|
||||||
|
this.options = options || {};
|
||||||
|
this.cookies = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a cookie string to the cookie storage
|
||||||
|
*
|
||||||
|
* @param {String} cookieStr Value from the 'Set-Cookie:' header
|
||||||
|
* @param {String} url Current URL
|
||||||
|
*/
|
||||||
|
set(cookieStr, url) {
|
||||||
|
let urlparts = urllib.parse(url || '');
|
||||||
|
let cookie = this.parse(cookieStr);
|
||||||
|
let domain;
|
||||||
|
|
||||||
|
if (cookie.domain) {
|
||||||
|
domain = cookie.domain.replace(/^\./, '');
|
||||||
|
|
||||||
|
// do not allow cross origin cookies
|
||||||
|
if (
|
||||||
|
// can't be valid if the requested domain is shorter than current hostname
|
||||||
|
urlparts.hostname.length < domain.length ||
|
||||||
|
// prefix domains with dot to be sure that partial matches are not used
|
||||||
|
('.' + urlparts.hostname).substr(-domain.length + 1) !== '.' + domain
|
||||||
|
) {
|
||||||
|
cookie.domain = urlparts.hostname;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cookie.domain = urlparts.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cookie.path) {
|
||||||
|
cookie.path = this.getPath(urlparts.pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no expire date, then use sessionTimeout value
|
||||||
|
if (!cookie.expires) {
|
||||||
|
cookie.expires = new Date(Date.now() + (Number(this.options.sessionTimeout || SESSION_TIMEOUT) || SESSION_TIMEOUT) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.add(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns cookie string for the 'Cookie:' header.
|
||||||
|
*
|
||||||
|
* @param {String} url URL to check for
|
||||||
|
* @returns {String} Cookie header or empty string if no matches were found
|
||||||
|
*/
|
||||||
|
get(url) {
|
||||||
|
return this.list(url)
|
||||||
|
.map(cookie => cookie.name + '=' + cookie.value)
|
||||||
|
.join('; ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all valied cookie objects for the specified URL
|
||||||
|
*
|
||||||
|
* @param {String} url URL to check for
|
||||||
|
* @returns {Array} An array of cookie objects
|
||||||
|
*/
|
||||||
|
list(url) {
|
||||||
|
let result = [];
|
||||||
|
let i;
|
||||||
|
let cookie;
|
||||||
|
|
||||||
|
for (i = this.cookies.length - 1; i >= 0; i--) {
|
||||||
|
cookie = this.cookies[i];
|
||||||
|
|
||||||
|
if (this.isExpired(cookie)) {
|
||||||
|
this.cookies.splice(i, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.match(cookie, url)) {
|
||||||
|
result.unshift(cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses cookie string from the 'Set-Cookie:' header
|
||||||
|
*
|
||||||
|
* @param {String} cookieStr String from the 'Set-Cookie:' header
|
||||||
|
* @returns {Object} Cookie object
|
||||||
|
*/
|
||||||
|
parse(cookieStr) {
|
||||||
|
let cookie = {};
|
||||||
|
|
||||||
|
(cookieStr || '')
|
||||||
|
.toString()
|
||||||
|
.split(';')
|
||||||
|
.forEach(cookiePart => {
|
||||||
|
let valueParts = cookiePart.split('=');
|
||||||
|
let key = valueParts.shift().trim().toLowerCase();
|
||||||
|
let value = valueParts.join('=').trim();
|
||||||
|
let domain;
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
// skip empty parts
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'expires':
|
||||||
|
value = new Date(value);
|
||||||
|
// ignore date if can not parse it
|
||||||
|
if (value.toString() !== 'Invalid Date') {
|
||||||
|
cookie.expires = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'path':
|
||||||
|
cookie.path = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'domain':
|
||||||
|
domain = value.toLowerCase();
|
||||||
|
if (domain.length && domain.charAt(0) !== '.') {
|
||||||
|
domain = '.' + domain; // ensure preceeding dot for user set domains
|
||||||
|
}
|
||||||
|
cookie.domain = domain;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'max-age':
|
||||||
|
cookie.expires = new Date(Date.now() + (Number(value) || 0) * 1000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'secure':
|
||||||
|
cookie.secure = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'httponly':
|
||||||
|
cookie.httponly = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!cookie.name) {
|
||||||
|
cookie.name = key;
|
||||||
|
cookie.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a cookie object is valid for a specified URL
|
||||||
|
*
|
||||||
|
* @param {Object} cookie Cookie object
|
||||||
|
* @param {String} url URL to check for
|
||||||
|
* @returns {Boolean} true if cookie is valid for specifiec URL
|
||||||
|
*/
|
||||||
|
match(cookie, url) {
|
||||||
|
let urlparts = urllib.parse(url || '');
|
||||||
|
|
||||||
|
// check if hostname matches
|
||||||
|
// .foo.com also matches subdomains, foo.com does not
|
||||||
|
if (
|
||||||
|
urlparts.hostname !== cookie.domain &&
|
||||||
|
(cookie.domain.charAt(0) !== '.' || ('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if path matches
|
||||||
|
let path = this.getPath(urlparts.pathname);
|
||||||
|
if (path.substr(0, cookie.path.length) !== cookie.path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check secure argument
|
||||||
|
if (cookie.secure && urlparts.protocol !== 'https:') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds (or updates/removes if needed) a cookie object to the cookie storage
|
||||||
|
*
|
||||||
|
* @param {Object} cookie Cookie value to be stored
|
||||||
|
*/
|
||||||
|
add(cookie) {
|
||||||
|
let i;
|
||||||
|
let len;
|
||||||
|
|
||||||
|
// nothing to do here
|
||||||
|
if (!cookie || !cookie.name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite if has same params
|
||||||
|
for (i = 0, len = this.cookies.length; i < len; i++) {
|
||||||
|
if (this.compare(this.cookies[i], cookie)) {
|
||||||
|
// check if the cookie needs to be removed instead
|
||||||
|
if (this.isExpired(cookie)) {
|
||||||
|
this.cookies.splice(i, 1); // remove expired/unset cookie
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cookies[i] = cookie;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add as new if not already expired
|
||||||
|
if (!this.isExpired(cookie)) {
|
||||||
|
this.cookies.push(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if two cookie objects are the same
|
||||||
|
*
|
||||||
|
* @param {Object} a Cookie to check against
|
||||||
|
* @param {Object} b Cookie to check against
|
||||||
|
* @returns {Boolean} True, if the cookies are the same
|
||||||
|
*/
|
||||||
|
compare(a, b) {
|
||||||
|
return a.name === b.name && a.path === b.path && a.domain === b.domain && a.secure === b.secure && a.httponly === a.httponly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a cookie is expired
|
||||||
|
*
|
||||||
|
* @param {Object} cookie Cookie object to check against
|
||||||
|
* @returns {Boolean} True, if the cookie is expired
|
||||||
|
*/
|
||||||
|
isExpired(cookie) {
|
||||||
|
return (cookie.expires && cookie.expires < new Date()) || !cookie.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns normalized cookie path for an URL path argument
|
||||||
|
*
|
||||||
|
* @param {String} pathname
|
||||||
|
* @returns {String} Normalized path
|
||||||
|
*/
|
||||||
|
getPath(pathname) {
|
||||||
|
let path = (pathname || '/').split('/');
|
||||||
|
path.pop(); // remove filename part
|
||||||
|
path = path.join('/').trim();
|
||||||
|
|
||||||
|
// ensure path prefix /
|
||||||
|
if (path.charAt(0) !== '/') {
|
||||||
|
path = '/' + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure path suffix /
|
||||||
|
if (path.substr(-1) !== '/') {
|
||||||
|
path += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Cookies;
|
||||||
281
node_modules/nodemailer/lib/fetch/index.js
generated
vendored
Normal file
281
node_modules/nodemailer/lib/fetch/index.js
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const urllib = require('url');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const PassThrough = require('stream').PassThrough;
|
||||||
|
const Cookies = require('./cookies');
|
||||||
|
const packageData = require('../../package.json');
|
||||||
|
const net = require('net');
|
||||||
|
const errors = require('../errors');
|
||||||
|
|
||||||
|
const MAX_REDIRECTS = 5;
|
||||||
|
|
||||||
|
module.exports = function (url, options) {
|
||||||
|
return nmfetch(url, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.Cookies = Cookies;
|
||||||
|
|
||||||
|
function nmfetch(url, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
options.fetchRes = options.fetchRes || new PassThrough();
|
||||||
|
options.cookies = options.cookies || new Cookies();
|
||||||
|
options.redirects = options.redirects || 0;
|
||||||
|
options.maxRedirects = isNaN(options.maxRedirects) ? MAX_REDIRECTS : options.maxRedirects;
|
||||||
|
|
||||||
|
if (options.cookie) {
|
||||||
|
[].concat(options.cookie || []).forEach(cookie => {
|
||||||
|
options.cookies.set(cookie, url);
|
||||||
|
});
|
||||||
|
options.cookie = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fetchRes = options.fetchRes;
|
||||||
|
let parsed = urllib.parse(url);
|
||||||
|
let method = (options.method || '').toString().trim().toUpperCase() || 'GET';
|
||||||
|
let finished = false;
|
||||||
|
let cookies;
|
||||||
|
let body;
|
||||||
|
|
||||||
|
let handler = parsed.protocol === 'https:' ? https : http;
|
||||||
|
|
||||||
|
let headers = {
|
||||||
|
'accept-encoding': 'gzip,deflate',
|
||||||
|
'user-agent': 'nodemailer/' + packageData.version
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(options.headers || {}).forEach(key => {
|
||||||
|
headers[key.toLowerCase().trim()] = options.headers[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.userAgent) {
|
||||||
|
headers['user-agent'] = options.userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.auth) {
|
||||||
|
headers.Authorization = 'Basic ' + Buffer.from(parsed.auth).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cookies = options.cookies.get(url))) {
|
||||||
|
headers.cookie = cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.body) {
|
||||||
|
if (options.contentType !== false) {
|
||||||
|
headers['Content-Type'] = options.contentType || 'application/x-www-form-urlencoded';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options.body.pipe === 'function') {
|
||||||
|
// it's a stream
|
||||||
|
headers['Transfer-Encoding'] = 'chunked';
|
||||||
|
body = options.body;
|
||||||
|
body.on('error', err => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (options.body instanceof Buffer) {
|
||||||
|
body = options.body;
|
||||||
|
} else if (typeof options.body === 'object') {
|
||||||
|
try {
|
||||||
|
// encodeURIComponent can fail on invalid input (partial emoji etc.)
|
||||||
|
body = Buffer.from(
|
||||||
|
Object.keys(options.body)
|
||||||
|
.map(key => {
|
||||||
|
let value = options.body[key].toString().trim();
|
||||||
|
return encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
||||||
|
})
|
||||||
|
.join('&')
|
||||||
|
);
|
||||||
|
} catch (E) {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
E.code = errors.EFETCH;
|
||||||
|
E.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', E);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body = Buffer.from(options.body.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
headers['Content-Type'] = options.contentType || 'application/x-www-form-urlencoded';
|
||||||
|
headers['Content-Length'] = body.length;
|
||||||
|
}
|
||||||
|
// if method is not provided, use POST instead of GET
|
||||||
|
method = (options.method || '').toString().trim().toUpperCase() || 'POST';
|
||||||
|
}
|
||||||
|
|
||||||
|
let req;
|
||||||
|
let reqOptions = {
|
||||||
|
method,
|
||||||
|
host: parsed.hostname,
|
||||||
|
path: parsed.path,
|
||||||
|
port: parsed.port ? parsed.port : parsed.protocol === 'https:' ? 443 : 80,
|
||||||
|
headers,
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
agent: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.tls) {
|
||||||
|
Object.keys(options.tls).forEach(key => {
|
||||||
|
reqOptions[key] = options.tls[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
parsed.protocol === 'https:' &&
|
||||||
|
parsed.hostname &&
|
||||||
|
parsed.hostname !== reqOptions.host &&
|
||||||
|
!net.isIP(parsed.hostname) &&
|
||||||
|
!reqOptions.servername
|
||||||
|
) {
|
||||||
|
reqOptions.servername = parsed.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
req = handler.request(reqOptions);
|
||||||
|
} catch (E) {
|
||||||
|
finished = true;
|
||||||
|
setImmediate(() => {
|
||||||
|
E.code = errors.EFETCH;
|
||||||
|
E.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', E);
|
||||||
|
});
|
||||||
|
return fetchRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.timeout) {
|
||||||
|
req.setTimeout(options.timeout, () => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
req.abort();
|
||||||
|
let err = new Error('Request Timeout');
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
req.on('error', err => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('response', res => {
|
||||||
|
let inflate;
|
||||||
|
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (res.headers['content-encoding']) {
|
||||||
|
case 'gzip':
|
||||||
|
case 'deflate':
|
||||||
|
inflate = zlib.createUnzip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.headers['set-cookie']) {
|
||||||
|
[].concat(res.headers['set-cookie'] || []).forEach(cookie => {
|
||||||
|
options.cookies.set(cookie, url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([301, 302, 303, 307, 308].includes(res.statusCode) && res.headers.location) {
|
||||||
|
// redirect
|
||||||
|
options.redirects++;
|
||||||
|
if (options.redirects > options.maxRedirects) {
|
||||||
|
finished = true;
|
||||||
|
let err = new Error('Maximum redirect count exceeded');
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
req.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// redirect does not include POST body
|
||||||
|
options.method = 'GET';
|
||||||
|
options.body = false;
|
||||||
|
return nmfetch(urllib.resolve(url, res.headers.location), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchRes.statusCode = res.statusCode;
|
||||||
|
fetchRes.headers = res.headers;
|
||||||
|
|
||||||
|
if (res.statusCode >= 300 && !options.allowErrorResponse) {
|
||||||
|
finished = true;
|
||||||
|
let err = new Error('Invalid status code ' + res.statusCode);
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
req.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.on('error', err => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
req.abort();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (inflate) {
|
||||||
|
res.pipe(inflate).pipe(fetchRes);
|
||||||
|
inflate.on('error', err => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
req.abort();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.pipe(fetchRes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
if (body) {
|
||||||
|
try {
|
||||||
|
if (typeof body.pipe === 'function') {
|
||||||
|
return body.pipe(req);
|
||||||
|
} else {
|
||||||
|
req.write(body);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
finished = true;
|
||||||
|
err.code = errors.EFETCH;
|
||||||
|
err.sourceUrl = url;
|
||||||
|
fetchRes.emit('error', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetchRes;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user