Initial commit
This commit is contained in:
commit
af97bccb0e
10 changed files with 548 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
76
.gitignore
vendored
Normal file
76
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"js/ts.implicitProjectConfig.checkJs": true
|
||||||
|
}
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Wildan M
|
||||||
|
|
||||||
|
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.
|
||||||
2
README.md
Normal file
2
README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# forward-domain
|
||||||
|
|
||||||
131
app.js
Normal file
131
app.js
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
// production endpoint (use pm2/phusion/whatever)
|
||||||
|
|
||||||
|
const argv = require('minimist')(process.argv.slice(2));
|
||||||
|
const app = require("./index.js");
|
||||||
|
|
||||||
|
const https = require('https');
|
||||||
|
const tls = require('tls');
|
||||||
|
const certnode = require('certnode')
|
||||||
|
const fs = require('fs');
|
||||||
|
const {
|
||||||
|
default: axios
|
||||||
|
} = require('axios');
|
||||||
|
const path = require('path');
|
||||||
|
const record_email_prefix = 'forward-domain-cert-maintainer=';
|
||||||
|
const client = new certnode.Client();
|
||||||
|
const certsDir = path.join(__dirname, '.certs');
|
||||||
|
var crypto = require('crypto');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<string, {cert: any, key: any, expire: number}>}
|
||||||
|
*/
|
||||||
|
const resolveCache = {};
|
||||||
|
|
||||||
|
function md5(str) {
|
||||||
|
return crypto.createHash('md5').update(str).digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCertCachePath(host) {
|
||||||
|
const hash = md5(host);
|
||||||
|
return path.join(certsDir, hash.substr(0, 2), hash.substr(2), host);
|
||||||
|
}
|
||||||
|
async function findMaintainerEmail(host) {
|
||||||
|
const resolve = await axios(`https://dns.google/resolve?name=${encodeURIComponent(host)}&type=TXT`);
|
||||||
|
for (const head of resolve.data.Answer) {
|
||||||
|
return head.data.slice(record_email_prefix.length);
|
||||||
|
}
|
||||||
|
throw new Error(record_email_prefix + ' TXT is missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildCache(host) {
|
||||||
|
const dir = getCertCachePath(host);
|
||||||
|
const keyP = path.join(dir, 'privateKey.pem');
|
||||||
|
const certP = path.join(dir, 'publicKey.pem');
|
||||||
|
const extP = path.join(dir, 'expire');
|
||||||
|
await ensureDir(dir);
|
||||||
|
try {
|
||||||
|
await fs.promises.access(keyP, fs.constants.R_OK | fs.constants.W_OK);
|
||||||
|
await fs.promises.access(certP, fs.constants.R_OK | fs.constants.W_OK);
|
||||||
|
await fs.promises.access(extP, fs.constants.R_OK | fs.constants.W_OK);
|
||||||
|
const expire = parseInt((await fs.promises.readFile(extP)).toString('utf8'));
|
||||||
|
if (Date.now() > expire)
|
||||||
|
throw null; // expired
|
||||||
|
const cert = await fs.promises.readFile(certP, 'utf8');
|
||||||
|
const key = await fs.promises.readFile(keyP, 'utf8')
|
||||||
|
return {
|
||||||
|
cert,
|
||||||
|
key,
|
||||||
|
expire
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const {
|
||||||
|
certificate,
|
||||||
|
privateKeyData
|
||||||
|
} = await client.generateCertificate(host, await findMaintainerEmail(host));
|
||||||
|
await fs.promises.writeFile(certP, certificate);
|
||||||
|
await certnode.writeKeyToFile(keyP, privateKeyData, '');
|
||||||
|
const expire = (Date.now() + 45 * 86400 * 1000);
|
||||||
|
await fs.promises.writeFile(extP, expire.toString());
|
||||||
|
return {
|
||||||
|
cert: certificate,
|
||||||
|
key: privateKeyData,
|
||||||
|
expire
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getKeyCert(servername) {
|
||||||
|
let cache = resolveCache[servername];
|
||||||
|
await ensureDir(certsDir);
|
||||||
|
if (!cache || (Date.now() > cache.expire)) {
|
||||||
|
cache = await buildCache(servername);
|
||||||
|
resolveCache[servername] = cache;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key: cache.key,
|
||||||
|
cert: cache.cert,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureDir(dir) {
|
||||||
|
try {
|
||||||
|
await fs.promises.access(dir, fs.constants.W_OK | fs.constants.O_DIRECTORY);
|
||||||
|
} catch (error) {
|
||||||
|
await fs.promises.mkdir(dir, {
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const main = async () => {
|
||||||
|
await client.generateAccountKeyPair()
|
||||||
|
await ensureDir(certsDir);
|
||||||
|
const httpsServer = https.createServer({
|
||||||
|
SNICallback: async (servername, ctx) => {
|
||||||
|
// Generate fresh account keys for Let's Encrypt
|
||||||
|
try {
|
||||||
|
return tls.createSecureContext(await getKeyCert(servername))
|
||||||
|
} catch (error) {
|
||||||
|
ctx(error, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, app.listeners[0]);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// if (!argv.maintainerEmail)
|
||||||
|
// throw new Error('--maintainerEmail is required');
|
||||||
|
|
||||||
|
// require("greenlock-express")
|
||||||
|
// .init({
|
||||||
|
// packageRoot: __dirname,
|
||||||
|
// configDir: "./greenlock.d",
|
||||||
|
// // contact for security and critical bug notices
|
||||||
|
// maintainerEmail: argv.maintainerEmail,
|
||||||
|
// // whether or not to run at cloudscale
|
||||||
|
// cluster: false
|
||||||
|
// })
|
||||||
|
// // Serves on 80 and 443
|
||||||
|
// // Get's SSL certificates magically!
|
||||||
|
// .serve(app);
|
||||||
60
index.js
Normal file
60
index.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// development endpoint (use ngrok)
|
||||||
|
|
||||||
|
const http = require('http');
|
||||||
|
const argv = require('minimist')(process.argv.slice(2));
|
||||||
|
const port = parseInt(argv.port || 3000);
|
||||||
|
const record_prefix = 'forward-domain=';
|
||||||
|
|
||||||
|
const {
|
||||||
|
default: axios
|
||||||
|
} = require('axios');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<string, {expire: number, expand: boolean, url: string}>}
|
||||||
|
*/
|
||||||
|
const resolveCache = {};
|
||||||
|
|
||||||
|
async function buildCache(host) {
|
||||||
|
const resolve = await axios(`https://dns.google/resolve?name=${encodeURIComponent(host)}&type=TXT`);
|
||||||
|
for (const head of resolve.data.Answer) {
|
||||||
|
let url = head.data.slice(record_prefix.length);
|
||||||
|
let expand = false;
|
||||||
|
if (url.endsWith('*')) {
|
||||||
|
url = url.substr(0, -1);
|
||||||
|
expand = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
expand,
|
||||||
|
expire: Date.now() + Math.max(head.TTL, 86400) * 1000,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(record_prefix + ' TXT is missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = http.createServer(async function (req, res) {
|
||||||
|
try {
|
||||||
|
let cache = resolveCache[req.headers.host];
|
||||||
|
if (!cache || (Date.now() > cache.expire)) {
|
||||||
|
cache = await buildCache(req.headers.host);
|
||||||
|
resolveCache[req.headers.host] = cache;
|
||||||
|
}
|
||||||
|
req.statusCode = 301;
|
||||||
|
req.headers.location = cache.expand ? cache.url + req.url : cache.url;
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
res.statusCode = 400;
|
||||||
|
res.write(error.message || 'Unknown error');
|
||||||
|
} finally {
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
server.listen(port, function () {
|
||||||
|
console.log(`server start at port ${port}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
module.exports = server
|
||||||
|
}
|
||||||
236
package-lock.json
generated
Normal file
236
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
{
|
||||||
|
"name": "forward-domain",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"certnode": "^0.0.1",
|
||||||
|
"minimist": "^1.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "0.21.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||||
|
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/certnode": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/certnode/-/certnode-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-zMdAVGR5t6bjpmmRzUvNrIZXBZ3bggHagnFZOJMDjyMWnxpIqtLBEsUsosH99XyvT2SvgJ+I0jGhkNN3lIog9w==",
|
||||||
|
"dependencies": {
|
||||||
|
"jose-node-cjs-runtime": "^3.12.2",
|
||||||
|
"pem": "^1.14.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/charenc": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/crypt": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es6-promisify": {
|
||||||
|
"version": "6.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
|
||||||
|
"integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg=="
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
|
||||||
|
"integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-buffer": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||||
|
},
|
||||||
|
"node_modules/isexe": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
|
},
|
||||||
|
"node_modules/jose-node-cjs-runtime": {
|
||||||
|
"version": "3.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/jose-node-cjs-runtime/-/jose-node-cjs-runtime-3.15.4.tgz",
|
||||||
|
"integrity": "sha512-YkfdukFlO54aqPQ/9H1W4KWkyjHNcw0GPMEVZOXrlgHwnN/wZ1+fiItKvFAAeYZZAzqmw+xMwRTLx4nl3K3ZoA==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/md5": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||||
|
"dependencies": {
|
||||||
|
"charenc": "0.0.2",
|
||||||
|
"crypt": "0.0.2",
|
||||||
|
"is-buffer": "~1.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||||
|
},
|
||||||
|
"node_modules/os-tmpdir": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pem": {
|
||||||
|
"version": "1.14.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pem/-/pem-1.14.4.tgz",
|
||||||
|
"integrity": "sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promisify": "^6.0.0",
|
||||||
|
"md5": "^2.2.1",
|
||||||
|
"os-tmpdir": "^1.0.1",
|
||||||
|
"which": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": {
|
||||||
|
"version": "0.21.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||||
|
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"certnode": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/certnode/-/certnode-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-zMdAVGR5t6bjpmmRzUvNrIZXBZ3bggHagnFZOJMDjyMWnxpIqtLBEsUsosH99XyvT2SvgJ+I0jGhkNN3lIog9w==",
|
||||||
|
"requires": {
|
||||||
|
"jose-node-cjs-runtime": "^3.12.2",
|
||||||
|
"pem": "^1.14.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"charenc": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
|
||||||
|
},
|
||||||
|
"crypt": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
|
||||||
|
},
|
||||||
|
"es6-promisify": {
|
||||||
|
"version": "6.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
|
||||||
|
"integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg=="
|
||||||
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
|
||||||
|
"integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA=="
|
||||||
|
},
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||||
|
},
|
||||||
|
"isexe": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
|
},
|
||||||
|
"jose-node-cjs-runtime": {
|
||||||
|
"version": "3.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/jose-node-cjs-runtime/-/jose-node-cjs-runtime-3.15.4.tgz",
|
||||||
|
"integrity": "sha512-YkfdukFlO54aqPQ/9H1W4KWkyjHNcw0GPMEVZOXrlgHwnN/wZ1+fiItKvFAAeYZZAzqmw+xMwRTLx4nl3K3ZoA=="
|
||||||
|
},
|
||||||
|
"md5": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||||
|
"requires": {
|
||||||
|
"charenc": "0.0.2",
|
||||||
|
"crypt": "0.0.2",
|
||||||
|
"is-buffer": "~1.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimist": {
|
||||||
|
"version": "1.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||||
|
},
|
||||||
|
"os-tmpdir": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||||
|
},
|
||||||
|
"pem": {
|
||||||
|
"version": "1.14.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pem/-/pem-1.14.4.tgz",
|
||||||
|
"integrity": "sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g==",
|
||||||
|
"requires": {
|
||||||
|
"es6-promisify": "^6.0.0",
|
||||||
|
"md5": "^2.2.1",
|
||||||
|
"os-tmpdir": "^1.0.1",
|
||||||
|
"which": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
package.json
Normal file
17
package.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "forward-domain",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"certnode": "^0.0.1",
|
||||||
|
"minimist": "^1.2.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
public/.gitkeep
Normal file
0
public/.gitkeep
Normal file
Loading…
Add table
editor.link_modal.header
Reference in a new issue