Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove this change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brunocroh i tried but nothing happened.

I think this is probably because of LF and CRLF thing. Changing that also didn't revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
"[markdown]": {
"editor.wordWrap": "off"
}
}
}
18 changes: 17 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions recipes/crypto-fips/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# `crypto.fips` DEP0093

This recipe provides a guide for migrating from the deprecated `crypto.fips` to `crypto.getFips()` and `crypto.setFips()`.

See [DEP0093](https://nodejs.org/api/deprecations.html#DEP0093).

## Examples

**Before:**

```js
// Using crypto.fips
crypto.fips;

// Using crypto.fips = true
crypto.fips = true;

// Using crypto.fips = false
crypto.fips = false;
```

**After:**

```js
// Using crypto.getFips()
crypto.getFips();

// Using crypto.setFips(true)
crypto.setFips(true);

// Using crypto.setFips(false)
crypto.setFips(false);
```
21 changes: 21 additions & 0 deletions recipes/crypto-fips/codemod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
schema_version: "1.0"
name: "@nodejs/crypto-fips"
version: 1.0.0
description: Handle DEP0093 via transforming `crypto.fips` to `crypto.getFips()` and `crypto.setFips()`
author: Usman S.
license: MIT
workflow: workflow.yaml
category: migration

targets:
languages:
- javascript
- typescript

keywords:
- transformation
- migration

registry:
access: public
visibility: public
24 changes: 24 additions & 0 deletions recipes/crypto-fips/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@nodejs/crypto-fips",
"version": "1.0.0",
"description": "Handle DEP0093 via transforming `crypto.fips` to `crypto.getFips()` and `crypto.setFips()`",
"type": "module",
"scripts": {
"test": "npx codemod jssg test -l typescript ./src/workflow.ts ./"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nodejs/userland-migrations.git",
"directory": "recipes/crypto-fips",
"bugs": "https://github.com/nodejs/userland-migrations/issues"
},
"author": "Usman S.",
"license": "MIT",
"homepage": "https://github.com/nodejs/userland-migrations/blob/main/recipes/crypto-fips/README.md",
"devDependencies": {
"@codemod.com/jssg-types": "^1.0.3"
},
"dependencies": {
"@nodejs/codemod-utils": "*"
}
}
99 changes: 99 additions & 0 deletions recipes/crypto-fips/src/workflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { getNodeImportStatements } from '@nodejs/codemod-utils/ast-grep/import-statement';
import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call';
import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path';
import type { SgRoot, Edit, SgNode } from '@codemod.com/jssg-types/main';

const escapeRegExp = (input: string) =>
input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

/**
* Transform function that converts deprecated crypto.fips calls
* to the new crypto.getFips() and crypto.setFips() syntax.
*
* Handles:
* 1. crypto.fips -> crypto.getFips()
* 2. crypto.fips = true -> crypto.setFips(true)
* 3. crypto.fips = false -> crypto.setFips(false)
*/
export default function transform(root: SgRoot): string | null {
const rootNode = root.root();
let hasChanges = false;
const edits: Edit[] = [];

const cryptoBases = new Set<string>(getAllCryptoFipsBasePaths(root));

// Handle crypto.fips = ... (value-modification)
const assignmentResult = replaceAssignments(rootNode, cryptoBases);
edits.push(...assignmentResult.edits);
hasChanges = assignmentResult.hasChanges;

// Handle crypto.fips (value-access)
const readResult = replaceReads(rootNode, cryptoBases);
edits.push(...readResult.edits);
hasChanges = readResult.hasChanges;

if (!hasChanges) return null;
return rootNode.commitEdits(edits);
}

function* getCryptoFipsBasePaths(statements: SgNode[]) {
for (const stmt of statements) {
const resolvedPath = resolveBindingPath(stmt, '$.fips');
if (!resolvedPath || !resolvedPath.includes('.')) continue;
yield resolvedPath.slice(0, resolvedPath.lastIndexOf('.'));
}
}

function* getAllCryptoFipsBasePaths(root: SgRoot) {
yield* getCryptoFipsBasePaths(getNodeRequireCalls(root, 'crypto'));
yield* getCryptoFipsBasePaths(getNodeImportStatements(root, 'crypto'));
}

function replaceAssignments(rootNode: SgNode, cryptoBases: Set<string>) {
const edits: Edit[] = [];
let hasChanges = false;

for (const base of cryptoBases) {
const assignments = rootNode.findAll({
rule: {
pattern: `${base}.fips = $VALUE`,
},
});

for (const assign of assignments) {
const valueText = assign.getMatch('VALUE')?.text() ?? '';
const basePropRegex = new RegExp(
`\\b${escapeRegExp(base)}\\.fips\\b`,
'g',
);
const transformedValue = valueText.replace(
basePropRegex,
`${base}.getFips()`,
);
edits.push(assign.replace(`${base}.setFips(${transformedValue})`));
hasChanges = true;
}
}

return { edits, hasChanges };
}

function replaceReads(rootNode: SgNode, cryptoBases: Set<string>) {
const edits: Edit[] = [];
let hasChanges = false;

for (const base of cryptoBases) {
const reads = rootNode.findAll({
rule: {
pattern: `${base}.fips`,
},
});

for (const read of reads) {
edits.push(read.replace(`${base}.getFips()`));
hasChanges = true;
}
}

return { edits, hasChanges };
}
5 changes: 5 additions & 0 deletions recipes/crypto-fips/tests/expected/file-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const crypto = require("node:crypto");

if (crypto.getFips()) {
console.log("FIPS mode is enabled");
}
3 changes: 3 additions & 0 deletions recipes/crypto-fips/tests/expected/file-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const crypto = require("node:crypto");

crypto.setFips(true);
6 changes: 6 additions & 0 deletions recipes/crypto-fips/tests/expected/file-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const crypto = require("node:crypto");

if (process.env.ENABLE_FIPS === "true") {
crypto.setFips(true);
}
console.log("FIPS enabled:", crypto.getFips());
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/expected/file-4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import crypto from "node:crypto";

const fipsStatus = crypto.getFips();
crypto.setFips(!fipsStatus);
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/expected/file-5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const nodeCrypto = require("node:crypto");

const currentFips = nodeCrypto.getFips();
nodeCrypto.setFips(!currentFips);
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/expected/file-6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const crypto = require("node:crypto");

console.log("FIPS enabled:", crypto.getFips());
crypto.setFips(crypto.getFips() || process.env.FORCE_FIPS);
5 changes: 5 additions & 0 deletions recipes/crypto-fips/tests/input/file-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const crypto = require("node:crypto");

if (crypto.fips) {
console.log("FIPS mode is enabled");
}
3 changes: 3 additions & 0 deletions recipes/crypto-fips/tests/input/file-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const crypto = require("node:crypto");

crypto.fips = true;
6 changes: 6 additions & 0 deletions recipes/crypto-fips/tests/input/file-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const crypto = require("node:crypto");

if (process.env.ENABLE_FIPS === "true") {
crypto.fips = true;
}
console.log("FIPS enabled:", crypto.fips);
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/input/file-4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import crypto from "node:crypto";

const fipsStatus = crypto.fips;
crypto.fips = !fipsStatus;
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/input/file-5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const nodeCrypto = require("node:crypto");

const currentFips = nodeCrypto.fips;
nodeCrypto.fips = !currentFips;
4 changes: 4 additions & 0 deletions recipes/crypto-fips/tests/input/file-6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const crypto = require("node:crypto");

console.log("FIPS enabled:", crypto.fips);
crypto.fips = crypto.fips || process.env.FORCE_FIPS;
23 changes: 23 additions & 0 deletions recipes/crypto-fips/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"allowImportingTsExtensions": true,
"allowJs": true,
"alwaysStrict": true,
"baseUrl": "./",
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"lib": ["ESNext", "DOM"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noImplicitThis": true,
"removeComments": true,
"strict": true,
"stripInternal": true,
"target": "esnext"
},
"include": ["./"],
"exclude": [
"tests/**"
]
}
25 changes: 25 additions & 0 deletions recipes/crypto-fips/workflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/codemod-com/codemod/refs/heads/main/schemas/workflow.json

version: "1"

nodes:
- id: apply-transforms
name: Apply AST Transformations
type: automatic
steps:
- name: Handle DEP0093 via transforming `crypto.fips` to `crypto.getFips()`, `crypto.setFips()` to `crypto.setFips(true)` and `crypto.setFips(false)`.
js-ast-grep:
js_file: src/workflow.ts
base_path: .
include:
- "**/*.js"
- "**/*.jsx"
- "**/*.mjs"
- "**/*.cjs"
- "**/*.cts"
- "**/*.mts"
- "**/*.ts"
- "**/*.tsx"
exclude:
- "**/node_modules/**"
language: typescript
Loading