@yunsoft/yuncms 0.1.25 → 0.1.27
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/package.json +3 -3
- package/src/update-lock.js +56 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yunsoft/yuncms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Command-line setup and runtime launcher for YunCMS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"test": "node --test"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@yunsoft/yuncms-api": "0.1.
|
|
34
|
-
"@yunsoft/yuncms-core": "0.1.
|
|
33
|
+
"@yunsoft/yuncms-api": "0.1.27",
|
|
34
|
+
"@yunsoft/yuncms-core": "0.1.27"
|
|
35
35
|
},
|
|
36
36
|
"funding": {
|
|
37
37
|
"type": "github",
|
package/src/update-lock.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { mkdir, open, rm } from 'node:fs/promises';
|
|
2
|
+
import { lstat, mkdir, open, readFile, rm } from 'node:fs/promises';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
assertSecureUserParentDir,
|
|
6
7
|
hashMaintenanceBypassToken,
|
|
8
|
+
legacyMaintenanceLockPath,
|
|
7
9
|
maintenanceLockPath,
|
|
10
|
+
probeLegacyMaintenanceLock,
|
|
8
11
|
} from '@yunsoft/yuncms-core';
|
|
9
12
|
|
|
10
|
-
export function updateLockPath(cwd = process.cwd()) {
|
|
11
|
-
return maintenanceLockPath(cwd);
|
|
13
|
+
export function updateLockPath(cwd = process.cwd(), options = {}) {
|
|
14
|
+
return maintenanceLockPath(cwd, options);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function legacyUpdateLockPath(cwd = process.cwd(), options = {}) {
|
|
18
|
+
return legacyMaintenanceLockPath(cwd, options);
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
export async function acquireUpdateLock({
|
|
@@ -16,10 +23,54 @@ export async function acquireUpdateLock({
|
|
|
16
23
|
now = new Date(),
|
|
17
24
|
pid = process.pid,
|
|
18
25
|
generateToken = () => randomBytes(32).toString('hex'),
|
|
26
|
+
tempRoot,
|
|
27
|
+
getuidFn,
|
|
28
|
+
userInfoFn,
|
|
29
|
+
readFileFn = readFile,
|
|
30
|
+
lstatFn = lstat,
|
|
19
31
|
} = {}) {
|
|
20
|
-
const
|
|
21
|
-
|
|
32
|
+
const options = {
|
|
33
|
+
cwd,
|
|
34
|
+
tempRoot,
|
|
35
|
+
getuidFn,
|
|
36
|
+
userInfoFn,
|
|
37
|
+
readFileFn,
|
|
38
|
+
lstatFn,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// 1. An accessible active or corrupt legacy lock blocks new CLI acquisition
|
|
42
|
+
let legacy;
|
|
43
|
+
try {
|
|
44
|
+
legacy = await probeLegacyMaintenanceLock(options);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (err?.code === 'YUNCMS_MAINTENANCE_ACTIVE') {
|
|
47
|
+
const locked = new Error(
|
|
48
|
+
`Another YunCMS backup/update/restore operation may already be running. Inspect and remove the stale lock only after verifying no operation is active: ${err.lockPath || legacyMaintenanceLockPath(cwd, options)}`,
|
|
49
|
+
);
|
|
50
|
+
locked.code = 'UPDATE_ALREADY_RUNNING';
|
|
51
|
+
locked.lockPath = err.lockPath || legacyMaintenanceLockPath(cwd, options);
|
|
52
|
+
locked.cause = err;
|
|
53
|
+
throw locked;
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (legacy) {
|
|
59
|
+
const locked = new Error(
|
|
60
|
+
`Another YunCMS backup/update/restore operation may already be running. Inspect and remove the stale lock only after verifying no operation is active: ${legacy.path}`,
|
|
61
|
+
);
|
|
62
|
+
locked.code = 'UPDATE_ALREADY_RUNNING';
|
|
63
|
+
locked.lockPath = legacy.path;
|
|
64
|
+
throw locked;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. Prepare per-user lock directory and validate security
|
|
68
|
+
const path = updateLockPath(cwd, options);
|
|
69
|
+
const parentDir = dirname(path);
|
|
70
|
+
await mkdir(parentDir, { recursive: true, mode: 0o700 });
|
|
71
|
+
await assertSecureUserParentDir(parentDir, { lstatFn, getuidFn });
|
|
22
72
|
|
|
73
|
+
// 3. Acquire exclusive lock file
|
|
23
74
|
let handle;
|
|
24
75
|
try {
|
|
25
76
|
handle = await open(path, 'wx', 0o600);
|