fscr 6.2.6 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -30
- package/dist/index.js +502 -186
- package/dist/lib/auth/auth-conf.js +49 -45
- package/dist/lib/cache/README.md +341 -0
- package/dist/lib/cache/cli.js +152 -0
- package/dist/lib/cache/file-watcher.js +193 -0
- package/dist/lib/cache/index.js +422 -0
- package/dist/lib/cache/monitor.js +224 -0
- package/dist/lib/commands/doctor.js +225 -0
- package/dist/lib/completions/completion.js +342 -0
- package/dist/lib/completions/generator.js +152 -0
- package/dist/lib/completions/scripts/bash.sh +108 -0
- package/dist/lib/completions/scripts/fish.sh +105 -0
- package/dist/lib/completions/scripts/powershell.ps1 +168 -0
- package/dist/lib/completions/scripts/zsh.sh +124 -0
- package/dist/lib/diagnostics/cache.js +121 -0
- package/dist/lib/diagnostics/fileSystem.js +236 -0
- package/dist/lib/diagnostics/gitCheck.js +41 -0
- package/dist/lib/diagnostics/nodeVersion.js +68 -0
- package/dist/lib/diagnostics/packageManager.js +64 -0
- package/dist/lib/diagnostics/performance.js +141 -0
- package/dist/lib/encryption/decryptConfig.js +3 -2
- package/dist/lib/encryption/encryption.js +153 -113
- package/dist/lib/generators/generateFScripts.js +16 -13
- package/dist/lib/generators/generateToc.js +23 -14
- package/dist/lib/generators/index.js +1 -1
- package/dist/lib/git/pub.js +27 -17
- package/dist/lib/git/taskRunner.js +79 -69
- package/dist/lib/git/validateNotDev.js +65 -54
- package/dist/lib/optionList.js +69 -57
- package/dist/lib/parsers/parseScriptsMd.cached.js +208 -0
- package/dist/lib/parsers/parseScriptsMd.js +88 -79
- package/dist/lib/parsers/parseScriptsPackage.js +4 -3
- package/dist/lib/performance/cache.js +199 -0
- package/dist/lib/performance/lazy-loader.js +189 -0
- package/dist/lib/performance/monitor.js +303 -0
- package/dist/lib/plugins/deployment/index.js +113 -0
- package/dist/lib/plugins/hooks.js +17 -0
- package/dist/lib/plugins/loader.js +91 -0
- package/dist/lib/plugins/task-notifier/index.js +72 -0
- package/dist/lib/release/bump.js +50 -45
- package/dist/lib/release/commitWithMessage.js +80 -52
- package/dist/lib/release/publish.js +19 -14
- package/dist/lib/release/pushToGit.js +40 -31
- package/dist/lib/release/releasenotes.js +116 -97
- package/dist/lib/release/seeChangedFiles.js +68 -60
- package/dist/lib/release/sort.js +200 -116
- package/dist/lib/release/tree.js +161 -147
- package/dist/lib/release/validateNotDev.js +52 -44
- package/dist/lib/running/index.js +1 -1
- package/dist/lib/running/runCLICommand.js +41 -31
- package/dist/lib/running/runParallel.js +61 -59
- package/dist/lib/running/runSequence.js +55 -53
- package/dist/lib/startScripts.js +129 -114
- package/dist/lib/taskList.js +97 -90
- package/dist/lib/test-files/.fscripts.md +113 -0
- package/dist/lib/test-files/.fscripts.test.md +103 -0
- package/dist/lib/test-files/.fscriptsb.md +107 -0
- package/dist/lib/test-files/.mdtest.md +40 -0
- package/dist/lib/test-files/consoleSample.js +13 -9
- package/dist/lib/test-files/inputSample.js +17 -14
- package/dist/lib/test-files/testConsole.js +1 -1
- package/dist/lib/test-files/testInput.js +1 -1
- package/dist/lib/upgradePackages.js +56 -46
- package/dist/lib/utils/clear.js +16 -13
- package/dist/lib/utils/console.js +27 -21
- package/dist/lib/utils/encryption.js +55 -13
- package/dist/lib/utils/hash.js +128 -0
- package/dist/lib/utils/helpers.js +153 -142
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/prompt.js +24 -29
- package/package.json +11 -29
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!-- toc -->
|
|
2
|
+
|
|
3
|
+
- [Build](#build)
|
|
4
|
+
* [v:publish](#vpublish)
|
|
5
|
+
* [script:js](#scriptjs)
|
|
6
|
+
- [Groups2](#groups2)
|
|
7
|
+
* [console:js](#consolejs)
|
|
8
|
+
* [input:js-](#inputjs-)
|
|
9
|
+
* [log:much:js](#logmuchjs)
|
|
10
|
+
|
|
11
|
+
<!-- tocstop -->
|
|
12
|
+
|
|
13
|
+
# Build
|
|
14
|
+
|
|
15
|
+
Build group description
|
|
16
|
+
|
|
17
|
+
## v:publish
|
|
18
|
+
|
|
19
|
+
Update v and push
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
sh publish.sh
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## script:js
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
const chalk = require("chalk");
|
|
29
|
+
console.log(`${chalk.underline.bold("RUNS JS\n\nt")}`);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
# Groups2
|
|
33
|
+
|
|
34
|
+
That darn second group!!!!!
|
|
35
|
+
|
|
36
|
+
## console:js
|
|
37
|
+
|
|
38
|
+
Only one script here with bash
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node src/sampleScripts/exampleLogTimeout.js
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## input:js-
|
|
45
|
+
|
|
46
|
+
Get some input from user
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node src/sampleScripts/exampleInput.js
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## log:much:js
|
|
53
|
+
|
|
54
|
+
Basically logs till yo momma says stop!
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
const chalk = require("chalk");
|
|
58
|
+
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
|
|
59
|
+
const quotes = [
|
|
60
|
+
"The trickster's functiowhat they reslly s function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they res function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they rewant, some sort of freedom. - Tom Robbins",
|
|
61
|
+
'"Disbelief in magic can really s function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they res function is to break taboos, create mischief, stir things up. In the end, the trickster gives people what they rewant, some sort of freedom. - Tom Robbins",\n' +
|
|
62
|
+
' "Disbelief in magic can force a poor soul into believing in government and business. - Tom Robbins',
|
|
63
|
+
'The trouble with the fasforce a poor soul into believing in government and business. - Tom Robbins",\n' +
|
|
64
|
+
' "The trouble with the fasforce a poor soul into believing in government and business. - Tom Robbins",\n' +
|
|
65
|
+
' "The trouble with the fast lane is that all the movement is horizontal. And I like to go vertical sometimes. - Tom Robbins',
|
|
66
|
+
"Our world isn't made of earth, air and water or even molecules and atoms; our world is made of language. - Tom Robbimade of earth, air and water or even molecules and atoms; our world is made of language. - Tom Robbins",
|
|
67
|
+
"I'm not infatuated with frivoith frivoith frivoith frivoith frivoith frivoith frivoith frivolousness. We're just good friends. - Tom Robbins",
|
|
68
|
+
"In fiction, when you paint yourself into a corner, you can write a pair of suction cups onto the bottoms of your shoes and walk up the wall and out the skylight and see the sun breaking through the clouds. In nonfiction, you don't have that luxury. - Tom Robbins"
|
|
69
|
+
];
|
|
70
|
+
let sxy;
|
|
71
|
+
const getOption = st => {
|
|
72
|
+
// if (Math.random() > 0.5) {
|
|
73
|
+
// st = st + sample(quotes) + sample(quotes) + sample(quotes);
|
|
74
|
+
// }
|
|
75
|
+
let options = [
|
|
76
|
+
chalk.blue(st),
|
|
77
|
+
chalk.underline.green(st),
|
|
78
|
+
chalk.green.bgRed.bold(st),
|
|
79
|
+
chalk.blue(st, st, st, st),
|
|
80
|
+
chalk.red(st, chalk.underline.bgBlue(st) + st)
|
|
81
|
+
];
|
|
82
|
+
return sample(options);
|
|
83
|
+
};
|
|
84
|
+
let isMil = 0;
|
|
85
|
+
const theRun = async () => {
|
|
86
|
+
return new Promise(resolve => {
|
|
87
|
+
sxy = setInterval(() => {
|
|
88
|
+
const qt = sample(quotes);
|
|
89
|
+
console.log(new Date() + " ------- ----- ---- \n");
|
|
90
|
+
console.log(getOption(qt));
|
|
91
|
+
console.log(new Date() + " ------- ----- ---- \n");
|
|
92
|
+
console.log("----- ---- \n");
|
|
93
|
+
console.log("----- ---- \n");
|
|
94
|
+
console.log("----- ---- \n");
|
|
95
|
+
if (isMil === 30) {
|
|
96
|
+
clearInterval(sxy);
|
|
97
|
+
console.log("DONE DONE DONE");
|
|
98
|
+
resolve();
|
|
99
|
+
} else {
|
|
100
|
+
isMil += 10;
|
|
101
|
+
}
|
|
102
|
+
}, 1000);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
theRun();
|
|
107
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# First category of scripts
|
|
2
|
+
|
|
3
|
+
Welcome to your new amazing .fscripts.md file. It replaces the headaches of npm scripts! But so much more.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## fsr
|
|
7
|
+
|
|
8
|
+
TBD
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
node bin/run
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## fsr:d
|
|
16
|
+
|
|
17
|
+
TBD
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
DEBUG=* node bin/run
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## deploy
|
|
25
|
+
|
|
26
|
+
TBD
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node src/utils/release/publish.js
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## pretty
|
|
34
|
+
|
|
35
|
+
TBD
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
prettier src/*.js --write
|
|
39
|
+
```
|
|
40
|
+
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import yargs from "yargs";
|
|
3
3
|
const argv = yargs(process.argv.slice(2)).argv;
|
|
4
|
+
|
|
4
5
|
(async function () {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
})
|
|
6
|
+
console.log(
|
|
7
|
+
`${chalk.green("PRE --- TEST 52")} ${process.argv.slice(2)} ${JSON.stringify(argv)}`
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
await new Promise((resolve) => {
|
|
11
|
+
setTimeout(() => {
|
|
12
|
+
console.log(`${chalk.green("ATTT --- TEST 52")}`);
|
|
13
|
+
resolve();
|
|
14
|
+
}, 3500);
|
|
15
|
+
});
|
|
16
|
+
console.log(`${chalk.green("POST --- TEST 52")}`);
|
|
17
|
+
})();
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
|
+
|
|
3
4
|
(async function () {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
})
|
|
5
|
+
console.log(`${chalk.green("PRE INPUT")}\n`);
|
|
6
|
+
inquirer
|
|
7
|
+
.prompt([
|
|
8
|
+
{
|
|
9
|
+
type: "list",
|
|
10
|
+
name: "category",
|
|
11
|
+
message: "What category do you want to run?",
|
|
12
|
+
choices: [1, 2, 3, 4, 5]
|
|
13
|
+
}
|
|
14
|
+
])
|
|
15
|
+
.then(({ category }) => {
|
|
16
|
+
console.log(`${chalk.green("CHOSEN ", category)}`);
|
|
17
|
+
});
|
|
18
|
+
console.log(`${chalk.green("POST INPUT")}`);
|
|
19
|
+
console.log("NODEENV", process.env.INPUT);
|
|
20
|
+
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
console.log("TEST CONSOLE OUTPUT");
|
|
1
|
+
console.log("TEST CONSOLE OUTPUT");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
const input = process.env.INPUT || 'default';
|
|
2
|
-
console.log(`INPUT: ${input}`);
|
|
2
|
+
console.log(`INPUT: ${input}`);
|
|
@@ -6,60 +6,70 @@ import { fileURLToPath } from "url";
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
const __dirname = path.dirname(__filename);
|
|
8
8
|
const logError = message => {
|
|
9
|
-
|
|
9
|
+
console.log(chalk.red("[Error]: " + message));
|
|
10
10
|
};
|
|
11
11
|
const logInfo = message => {
|
|
12
|
-
|
|
12
|
+
console.log(chalk.blue("[Start]: " + message));
|
|
13
13
|
};
|
|
14
14
|
const logSuccess = message => {
|
|
15
|
-
|
|
15
|
+
console.log(chalk.green("[Done]: " + message));
|
|
16
16
|
};
|
|
17
|
+
|
|
17
18
|
let global = "";
|
|
18
19
|
let packagePath = path.resolve(process.cwd(), "package.json");
|
|
19
|
-
|
|
20
|
-
logError("Cannot find package.json file in the current directory");
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
24
|
-
let ignorePkgs = [];
|
|
20
|
+
|
|
25
21
|
const upgradePackages = async () => {
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
22
|
+
// Read package.json lazily so importing this module never crashes in a dir without one.
|
|
23
|
+
if (!fs.existsSync(packagePath)) {
|
|
24
|
+
logError("Cannot find package.json file in the current directory");
|
|
25
|
+
process.exit(1);
|
|
29
26
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
27
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
28
|
+
let ignorePkgs = [];
|
|
29
|
+
if (packageJson["fscripts"]) {
|
|
30
|
+
if (packageJson["fscripts"]["ignore-upgrade"]) {
|
|
31
|
+
ignorePkgs = packageJson["fscripts"]["ignore-upgrade"];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let upgraded = { before: {}, after: {} };
|
|
35
|
+
for (let element of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
36
|
+
if (packageJson[element]) {
|
|
37
|
+
const packages = Object.keys(packageJson[element]);
|
|
38
|
+
let packagesList = packages
|
|
39
|
+
.filter(pkk => !ignorePkgs.includes(pkk))
|
|
40
|
+
.map(pkk => {
|
|
41
|
+
upgraded["before"][pkk] = packageJson[element][pkk];
|
|
42
|
+
return pkk + "@latest";
|
|
43
|
+
})
|
|
44
|
+
.join(" ");
|
|
45
|
+
let command = `yarn add ${packagesList}`;
|
|
46
|
+
try {
|
|
47
|
+
// logInfo(command);
|
|
48
|
+
childProcess.execSync(command, {
|
|
49
|
+
stdio: "inherit",
|
|
50
|
+
env: Object.assign({}, process.env, {
|
|
51
|
+
FORCE_COLOR: true,
|
|
52
|
+
PATH: `${path.resolve("node_modules")}:${process.env.PATH}`
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
const packageJsonAfter = JSON.parse(fs.readFileSync(packagePath));
|
|
56
|
+
const packagesAfter = Object.keys(packageJsonAfter[element]);
|
|
57
|
+
let packagesListAfter = packagesAfter
|
|
58
|
+
.filter(pkk => !ignorePkgs.includes(pkk))
|
|
59
|
+
.map(pkk => {
|
|
60
|
+
upgraded["after"][pkk] = packageJsonAfter[element][pkk];
|
|
61
|
+
return upgraded["before"][pkk] !== upgraded["after"][pkk]
|
|
62
|
+
? `Updated: ${pkk} from: ${upgraded["before"][pkk]} | to: ${
|
|
63
|
+
upgraded["after"][pkk]
|
|
64
|
+
}\n`
|
|
65
|
+
: ``;
|
|
66
|
+
})
|
|
67
|
+
.join("");
|
|
68
|
+
logSuccess(packagesListAfter);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
logError(`${command} - ${e}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
62
73
|
}
|
|
63
|
-
}
|
|
64
74
|
};
|
|
65
|
-
export default upgradePackages;
|
|
75
|
+
export default upgradePackages;
|
package/dist/lib/utils/clear.js
CHANGED
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
* @param opts pass true to fully clear
|
|
4
4
|
*/
|
|
5
5
|
export default function clear(opts) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
if (typeof opts === "boolean") {
|
|
7
|
+
opts = {
|
|
8
|
+
fullClear: opts
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
opts = opts || {};
|
|
13
|
+
|
|
14
|
+
opts.fullClear = opts.hasOwnProperty("fullClear") ? opts.fullClear : true;
|
|
15
|
+
|
|
16
|
+
if (opts.fullClear === true) {
|
|
17
|
+
process.stdout.write("\x1b[2J");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
process.stdout.write("\x1b[0f");
|
|
21
|
+
};
|
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
import { timestamp } from "./helpers.js";
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
+
|
|
3
4
|
const d = timestamp();
|
|
5
|
+
|
|
4
6
|
const colors = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Reset: "\x1b[0m",
|
|
8
|
+
Red: "\x1b[31m",
|
|
9
|
+
Green: "\x1b[32m",
|
|
10
|
+
Yellow: "\x1b[33m"
|
|
9
11
|
};
|
|
12
|
+
|
|
10
13
|
const infoLog = console.info;
|
|
11
14
|
const logLog = console.log;
|
|
12
15
|
const warnLog = console.warn;
|
|
13
16
|
const errorLog = console.error;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
console.log = function(args) {
|
|
19
|
+
const copyArgs = Array.prototype.slice.call(arguments);
|
|
20
|
+
copyArgs.unshift(`${chalk.gray(d)} ${chalk.gray.bold("[LOG]")}️`);
|
|
21
|
+
infoLog.apply(null, copyArgs);
|
|
18
22
|
};
|
|
19
|
-
console.info = function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
console.info = function(args) {
|
|
24
|
+
const copyArgs = Array.prototype.slice.call(arguments);
|
|
25
|
+
copyArgs.unshift(`${chalk.gray(d)} ${chalk.blue.bold("i [INFO]")}️`);
|
|
26
|
+
infoLog.apply(null, copyArgs);
|
|
23
27
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
console.warn = function(args) {
|
|
30
|
+
const copyArgs = Array.prototype.slice.call(arguments);
|
|
31
|
+
copyArgs.unshift(`${chalk.gray(d)} ${chalk.yellow.bold("⚠ [WARN]")}️`);
|
|
32
|
+
warnLog.apply(null, copyArgs);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
console.error = function(args) {
|
|
36
|
+
const copyArgs = Array.prototype.slice.call(arguments);
|
|
37
|
+
copyArgs.unshift(`${chalk.gray(d)} ${chalk.red.bold("× [ERROR]")}️`);
|
|
38
|
+
warnLog.apply(null, copyArgs);
|
|
28
39
|
};
|
|
29
|
-
console.error = function (args) {
|
|
30
|
-
const copyArgs = Array.prototype.slice.call(arguments);
|
|
31
|
-
copyArgs.unshift(`${chalk.gray(d)} ${chalk.red.bold("× [ERROR]")}️`);
|
|
32
|
-
warnLog.apply(null, copyArgs);
|
|
33
|
-
};
|
|
@@ -1,18 +1,60 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
// OpenSSL / CryptoJS-compatible AES-256-CBC.
|
|
4
|
+
// Output format matches `CryptoJS.AES.encrypt(text, password).toString()` and
|
|
5
|
+
// `openssl enc -aes-256-cbc -salt -base64`: base64("Salted__" + 8-byte salt + ciphertext).
|
|
6
|
+
const algorithm = "aes-256-cbc";
|
|
7
|
+
const MAGIC = Buffer.from("Salted__", "utf8");
|
|
8
|
+
|
|
9
|
+
// OpenSSL EVP_BytesToKey (MD5) key+IV derivation from password + salt.
|
|
10
|
+
const deriveKeyIv = (password, salt) => {
|
|
11
|
+
const pass = Buffer.from(password, "utf8");
|
|
12
|
+
let data = Buffer.alloc(0);
|
|
13
|
+
let block = Buffer.alloc(0);
|
|
14
|
+
while (data.length < 48) {
|
|
15
|
+
// 32-byte key + 16-byte IV
|
|
16
|
+
block = crypto.createHash("md5").update(Buffer.concat([block, pass, salt])).digest();
|
|
17
|
+
data = Buffer.concat([data, block]);
|
|
18
|
+
}
|
|
19
|
+
return { key: data.subarray(0, 32), iv: data.subarray(32, 48) };
|
|
20
|
+
};
|
|
21
|
+
|
|
4
22
|
const encrypt = (toEncrypt, password) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
const salt = crypto.randomBytes(8);
|
|
24
|
+
const { key, iv } = deriveKeyIv(password, salt);
|
|
25
|
+
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
26
|
+
const ciphertext = Buffer.concat([
|
|
27
|
+
cipher.update(Buffer.from(toEncrypt, "utf8")),
|
|
28
|
+
cipher.final()
|
|
29
|
+
]);
|
|
30
|
+
return Buffer.concat([MAGIC, salt, ciphertext]).toString("base64");
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const decryptLegacy = (toDecrypt, password) => {
|
|
34
|
+
const key = crypto.scryptSync(password, "salt", 24);
|
|
35
|
+
const iv = Buffer.alloc(16, 0);
|
|
36
|
+
const decipher = crypto.createDecipheriv("aes-192-cbc", key, iv);
|
|
37
|
+
let decrypted = decipher.update(String(toDecrypt).trim(), "hex", "utf8");
|
|
38
|
+
decrypted += decipher.final("utf8");
|
|
39
|
+
return decrypted;
|
|
10
40
|
};
|
|
41
|
+
|
|
11
42
|
const decrypt = (toDecrypt, password) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
43
|
+
const raw = String(toDecrypt).trim();
|
|
44
|
+
const data = Buffer.from(raw, "base64");
|
|
45
|
+
if (!data.subarray(0, 8).equals(MAGIC)) {
|
|
46
|
+
// legacy format: hex-encoded AES-192-CBC
|
|
47
|
+
return decryptLegacy(raw, password);
|
|
48
|
+
}
|
|
49
|
+
const salt = data.subarray(8, 16);
|
|
50
|
+
const ciphertext = data.subarray(16);
|
|
51
|
+
const { key, iv } = deriveKeyIv(password, salt);
|
|
52
|
+
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
53
|
+
try {
|
|
54
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
55
|
+
} catch (e) {
|
|
56
|
+
throw new Error("Decryption failed — wrong password or corrupted file");
|
|
57
|
+
}
|
|
17
58
|
};
|
|
18
|
-
|
|
59
|
+
|
|
60
|
+
export { decrypt, encrypt };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash utilities for cache key generation
|
|
3
|
+
* @module utils/hash
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createHash } from 'crypto';
|
|
7
|
+
import { statSync } from 'fs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a SHA-256 hash from a string
|
|
11
|
+
* @param {string} input - Input string
|
|
12
|
+
* @param {number} [length=16] - Output length (characters)
|
|
13
|
+
* @returns {string} Hash string
|
|
14
|
+
*/
|
|
15
|
+
export function hash(input, length = 16) {
|
|
16
|
+
return createHash('sha256')
|
|
17
|
+
.update(input)
|
|
18
|
+
.digest('hex')
|
|
19
|
+
.substring(0, length);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a hash from multiple inputs
|
|
24
|
+
* @param {...string} inputs - Input strings
|
|
25
|
+
* @returns {string} Combined hash
|
|
26
|
+
*/
|
|
27
|
+
export function hashMultiple(...inputs) {
|
|
28
|
+
const combined = inputs.join(':');
|
|
29
|
+
return hash(combined);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a cache key from file path and metadata
|
|
34
|
+
* @param {string} filePath - File path
|
|
35
|
+
* @param {Object} [options] - Additional options
|
|
36
|
+
* @param {boolean} [options.includeMtime=true] - Include modification time
|
|
37
|
+
* @param {boolean} [options.includeSize=false] - Include file size
|
|
38
|
+
* @returns {string} Cache key
|
|
39
|
+
*/
|
|
40
|
+
export function generateFileKey(filePath, options = {}) {
|
|
41
|
+
const includeMtime = options.includeMtime !== false;
|
|
42
|
+
const includeSize = options.includeSize || false;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const stats = statSync(filePath);
|
|
46
|
+
const parts = [filePath];
|
|
47
|
+
|
|
48
|
+
if (includeMtime) {
|
|
49
|
+
parts.push(stats.mtimeMs.toString());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (includeSize) {
|
|
53
|
+
parts.push(stats.size.toString());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return hash(parts.join(':'));
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new Error(`Failed to generate file key for ${filePath}: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Generate a cache key from an object
|
|
64
|
+
* @param {Object} obj - Object to hash
|
|
65
|
+
* @returns {string} Cache key
|
|
66
|
+
*/
|
|
67
|
+
export function hashObject(obj) {
|
|
68
|
+
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
|
69
|
+
return hash(str);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generate a cache key from file path and content hash
|
|
74
|
+
* @param {string} filePath - File path
|
|
75
|
+
* @param {string} content - File content
|
|
76
|
+
* @returns {string} Cache key
|
|
77
|
+
*/
|
|
78
|
+
export function generateContentKey(filePath, content) {
|
|
79
|
+
const contentHash = hash(content);
|
|
80
|
+
return hash(`${filePath}:${contentHash}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get file metadata for cache validation
|
|
85
|
+
* @param {string} filePath - File path
|
|
86
|
+
* @returns {Object} File metadata
|
|
87
|
+
*/
|
|
88
|
+
export function getFileMetadata(filePath) {
|
|
89
|
+
try {
|
|
90
|
+
const stats = statSync(filePath);
|
|
91
|
+
return {
|
|
92
|
+
mtime: stats.mtimeMs,
|
|
93
|
+
size: stats.size,
|
|
94
|
+
exists: true
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return {
|
|
98
|
+
mtime: null,
|
|
99
|
+
size: null,
|
|
100
|
+
exists: false
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check if file has changed based on metadata
|
|
107
|
+
* @param {string} filePath - File path
|
|
108
|
+
* @param {number} cachedMtime - Cached modification time
|
|
109
|
+
* @returns {boolean} True if file has changed
|
|
110
|
+
*/
|
|
111
|
+
export function hasFileChanged(filePath, cachedMtime) {
|
|
112
|
+
try {
|
|
113
|
+
const stats = statSync(filePath);
|
|
114
|
+
return stats.mtimeMs !== cachedMtime;
|
|
115
|
+
} catch {
|
|
116
|
+
return true; // Consider changed if file doesn't exist
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default {
|
|
121
|
+
hash,
|
|
122
|
+
hashMultiple,
|
|
123
|
+
hashObject,
|
|
124
|
+
generateFileKey,
|
|
125
|
+
generateContentKey,
|
|
126
|
+
getFileMetadata,
|
|
127
|
+
hasFileChanged
|
|
128
|
+
};
|