Skip to content

Commit 8eb426d

Browse files
committed
settings Windows file/dir permissions in nodejs is not well-worn in the nodejs ecosystem. I'm trying to set the file/dir as offline to simulate it being otherwise inaccessible.
1 parent bfcb5e8 commit 8eb426d

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-node-api-modules/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"devDependencies": {
8484
"@babel/core": "^7.26.10",
8585
"@babel/types": "^7.27.0",
86+
"fswin": "^3.24.829",
8687
"metro-config": "0.81.1",
8788
"node-api-headers": "^1.5.0",
8889
"zod": "^3.24.3"

packages/react-native-node-api-modules/src/node/path-utils.test.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
22
import { describe, it } from "node:test";
33
import path from "node:path";
44
import fs from "node:fs";
5+
import fswin from "fswin";
56

67
import {
78
determineModuleContext,
@@ -13,6 +14,40 @@ import {
1314
} from "./path-utils.js";
1415
import { setupTempDirectory } from "./test-utils.js";
1516

17+
function removeReadPermissions(p: string) {
18+
if (process.platform === "win32") {
19+
// Windows: simulate unreadable by setting file to offline
20+
const attributes = {
21+
IS_READ_ONLY: true,
22+
IS_OFFLINE: true,
23+
IS_TEMPORARY: true,
24+
};
25+
26+
const result = fswin.setAttributesSync(p, attributes);
27+
if (!result) console.error('!!!!! can not set attributes');
28+
} else {
29+
// Unix-like: clear all perms
30+
fs.chmodSync(p, 0);
31+
}
32+
}
33+
34+
function restoreReadPermissions(p: string) {
35+
if (process.platform === "win32") {
36+
// Windows: simulate unreadable by setting file to offline
37+
const attributes = {
38+
IS_READ_ONLY: false,
39+
IS_OFFLINE: false,
40+
IS_TEMPORARY: false,
41+
};
42+
43+
const result = fswin.setAttributesSync(p, attributes);
44+
if (!result) console.error('!!!!! can not set attributes');
45+
} else {
46+
// Unix-like: clear all perms
47+
fs.chmodSync(p, 0o700);
48+
}
49+
}
50+
1651
describe("isNodeApiModule", () => {
1752
it("returns true for .node", (context) => {
1853
const tempDirectoryPath = setupTempDirectory(context, {
@@ -28,14 +63,14 @@ describe("isNodeApiModule", () => {
2863
"addon.android.node": "",
2964
});
3065
// remove read permissions on directory
31-
fs.chmodSync(tempDirectoryPath, 0);
66+
removeReadPermissions(tempDirectoryPath);
3267
try {
3368
assert.equal(
3469
isNodeApiModule(path.join(tempDirectoryPath, "addon")),
3570
false
3671
);
3772
} finally {
38-
fs.chmodSync(tempDirectoryPath, 0o700);
73+
restoreReadPermissions(tempDirectoryPath);
3974
}
4075
});
4176

@@ -45,14 +80,14 @@ describe("isNodeApiModule", () => {
4580
});
4681
const candidate = path.join(tempDirectoryPath, "addon.android.node");
4782
// remove read permission on file
48-
fs.chmodSync(candidate, 0);
83+
removeReadPermissions(candidate);
4984
try {
5085
assert.throws(
5186
() => isNodeApiModule(path.join(tempDirectoryPath, "addon")),
5287
/Found an unreadable module addon\.android\.node/
5388
);
5489
} finally {
55-
fs.chmodSync(candidate, 0o600);
90+
restoreReadPermissions(candidate);
5691
}
5792
});
5893

@@ -81,12 +116,12 @@ describe("isNodeApiModule", () => {
81116
});
82117
const unreadable = path.join(tempDirectoryPath, "addon.android.node");
83118
// only android module is unreadable
84-
fs.chmodSync(unreadable, 0);
119+
removeReadPermissions(unreadable);
85120
assert.throws(
86121
() => isNodeApiModule(path.join(tempDirectoryPath, "addon")),
87122
/Found an unreadable module addon\.android\.node/
88123
);
89-
fs.chmodSync(unreadable, 0o600);
124+
restoreReadPermissions(unreadable);
90125
});
91126
});
92127

packages/react-native-node-api-modules/src/node/path-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export function normalizeModulePath(modulePath: string) {
135135
const dirname = path.normalize(path.dirname(modulePath));
136136
const basename = path.basename(modulePath);
137137
const strippedBasename = stripExtension(basename).replace(/^lib/, "");
138+
// Replace backslashes with forward slashes for cross-platform compatibility
138139
return path.join(dirname, strippedBasename).replace(/\\/g, "/");
139140
}
140141

0 commit comments

Comments
 (0)